Repository: go
Issue: proposal: crypto/x509: Add support for PKCS#10 attributes
Labels: Proposal,Proposal-Crypto

Certificate signing requests also feature other attributes than Extensions.

There are protocols like [RFC 7030: Enrollment over Secure Transport (EST)](https://www.rfc-editor.org/rfc/rfc7030.html) and RFC [RFC 8894: Simple Certificate Enrolment Protocol](https://www.rfc-editor.org/rfc/rfc8894.html) that supports usage of 'challengePassword' attribute.

There are also other attributes that some party might be needing to use. Example attributes can be found from [PKCS #9: Selected Object Classes and Attribute Types Version 2.0](https://www.rfc-editor.org/rfc/rfc2985.html) (including specification for `challengePassword` attribute).

Currently it is a bit hard to access this information from application code. This requires copying parts of the `src/crypto/x509/x509.go` into your own application and then modifying them in order to access the details. One needs to access `RawTBSCertificateRequest` and from there `RawAttributes` and then do `ASN.1` parsing.

There exists `x509.parseRawAttributes()` function to parse `PKCS#10` attributes into `CertificateRequest.Attributes` but that cannot handle (as commented) the "simple" attributes. `CertificateRequest.Attributes` also has been marked as deprecated in favor of `CertificateRequest.Extensions`.

There is also old issue https://github.com/golang/go/issues/15995 describing some workarounds for accessing the information.

Instead of having those local hacks the proposal here is to export the needed information.

In order not to break previous software that might be using those fields new field and struct is proposed to be added.

Proposed API change is:
```patch
diff --git a/src/crypto/x509/x509.go b/src/crypto/x509/x509.go
index 9d80b1d8ba..1e5220539e 100644
--- a/src/crypto/x509/x509.go
+++ b/src/crypto/x509/x509.go
@@ -1794,6 +1794,9 @@ type CertificateRequest struct {
        // generating the requestedExtensions attribute.
        Attributes []pkix.AttributeTypeAndValueSET
 
+       // Pkcs10Attributes contains the CSR attributes that are not pkix.Extension's
+       Pkcs10Attributes []Pkcs10Attribute
+
        // Extensions contains all requested extensions, in raw form. When parsing
        // CSRs, this can be used to extract extensions that are not parsed by this
        // package.
@@ -1815,6 +1818,12 @@ type CertificateRequest struct {
        URIs           []*url.URL
 }
 
+// Pkcs10Attribute reflects the Attribute structure from RFC 2986, Section 4.1.
+type Pkcs10Attribute struct {
+       Id     asn1.ObjectIdentifier
+       Values []asn1.RawValue `asn1:"set"`
+}
+
 // These structures reflect the ASN.1 structure of X.509 certificate
 // signature requests (see RFC 2986):
 
```

Structure `pkcs10Attribute` from `x509.parseCSRExtensions()` is now promoted to be exported as `x509.Pkcs10Attribute`

Then access for in example for `challengePassword` would be:
```go
var oidChallengePassword = asn1.ObjectIdentifier{1, 2, 840, 113549, 1, 9, 7}

func GetChallengePassword(request *x509.CertificateRequest) (string, error) {
	var challengePassword string

	for _, pkcs10attribute := range request.Pkcs10Attributes {
		switch {
		case pkcs10attribute.Id.Equal(oidChallengePassword):
			_, err := asn1.Unmarshal(pkcs10attribute.Values[0].FullBytes, &challengePassword)
			if err != nil {
				return "", err
			}
			return challengePassword, nil
		}
	}

	return "", nil
}
```

There is `pkix.AttributeTypeAndValue` and that has been [proposed](https://go-review.googlesource.com/c/go/+/8160/3#message-cfcc37c4cc43b464f78a776885bdbe2846f7e4b0) for this use but that is missing value type and `asn1` parser guidance.

Note: it might be a good idea to have OID registry available as API for easier access for different attributes. In example `x509.OidChallengePassword` could be defined in the library.

Alternative implementation could be to add `CertificateRequest.ChallengePassowrd` to give access for the needed `challengePassowrd` value.

In here there was only example for using it (as that was the present need) but there should also be support for creating the certificate signing request with the `challengePassword`.