88 "crypto/x509/pkix"
99 "encoding/asn1"
1010 "encoding/json"
11+ "errors"
12+ "fmt"
1113
12- "github.com/pkg/errors"
1314 "go.step.sm/crypto/internal/utils"
1415 "golang.org/x/crypto/cryptobyte"
1516 cryptobyte_asn1 "golang.org/x/crypto/cryptobyte/asn1"
@@ -53,6 +54,10 @@ type CertificateRequest struct {
5354 URIs MultiURL `json:"uris"`
5455 SANs []SubjectAlternativeName `json:"sans"`
5556 Extensions []Extension `json:"extensions"`
57+ KeyUsage KeyUsage `json:"keyUsage"`
58+ ExtKeyUsage ExtKeyUsage `json:"extKeyUsage"`
59+ UnknownExtKeyUsage UnknownExtKeyUsage `json:"unknownExtKeyUsage"`
60+ BasicConstraints * BasicConstraints `json:"basicConstraints"`
5661 SignatureAlgorithm SignatureAlgorithm `json:"signatureAlgorithm"`
5762 ChallengePassword string `json:"-"`
5863 PublicKey interface {} `json:"-"`
@@ -83,7 +88,7 @@ func NewCertificateRequest(signer crypto.Signer, opts ...Option) (*CertificateRe
8388 // With templates
8489 var cr CertificateRequest
8590 if err := json .NewDecoder (o .CertBuffer ).Decode (& cr ); err != nil {
86- return nil , errors . Wrap ( err , "error unmarshaling certificate" )
91+ return nil , fmt . Errorf ( "error unmarshaling certificate: %w" , err )
8792 }
8893 cr .PublicKey = pub
8994 cr .Signer = signer
@@ -100,6 +105,33 @@ func NewCertificateRequest(signer crypto.Signer, opts ...Option) (*CertificateRe
100105 cr .Extensions = append ([]Extension {ext }, cr .Extensions ... )
101106 }
102107
108+ // Add KeyUsage extension if necessary.
109+ if cr .KeyUsage != 0 && ! cr .hasExtension (oidExtensionKeyUsage ) {
110+ ext , err := cr .KeyUsage .Extension ()
111+ if err != nil {
112+ return nil , err
113+ }
114+ cr .Extensions = append ([]Extension {ext }, cr .Extensions ... )
115+ }
116+
117+ // Add ExtKeyUsage extension if necessary.
118+ if len (cr .ExtKeyUsage ) > 0 || len (cr .UnknownExtKeyUsage ) > 0 {
119+ ext , err := cr .ExtKeyUsage .Extension (cr .UnknownExtKeyUsage )
120+ if err != nil {
121+ return nil , err
122+ }
123+ cr .Extensions = append ([]Extension {ext }, cr .Extensions ... )
124+ }
125+
126+ // Add BasicConstraints extension if necessary.
127+ if cr .BasicConstraints != nil {
128+ ext , err := cr .BasicConstraints .Extension ()
129+ if err != nil {
130+ return nil , err
131+ }
132+ cr .Extensions = append ([]Extension {ext }, cr .Extensions ... )
133+ }
134+
103135 return & cr , nil
104136}
105137
@@ -114,6 +146,12 @@ func NewCertificateRequest(signer crypto.Signer, opts ...Option) (*CertificateRe
114146func NewCertificateRequestFromX509 (cr * x509.CertificateRequest ) * CertificateRequest {
115147 // Set SubjectAltName extension as critical if Subject is empty.
116148 fixSubjectAltName (cr )
149+ // Extracts key usage, extended key usage, and basic constraints from the
150+ // certificate extensions. For backward compatibility, this method does not
151+ // return an error if an extension is improperly encoded or cannot be
152+ // decoded. In such cases, the extension is simply ignored.
153+ parsed , _ := parseCertificateRequestExtensions (cr .Extensions )
154+
117155 return & CertificateRequest {
118156 Version : cr .Version ,
119157 Subject : newSubject (cr .Subject ),
@@ -123,6 +161,10 @@ func NewCertificateRequestFromX509(cr *x509.CertificateRequest) *CertificateRequ
123161 IPAddresses : cr .IPAddresses ,
124162 URIs : cr .URIs ,
125163 Extensions : newExtensions (cr .Extensions ),
164+ KeyUsage : parsed .KeyUsage ,
165+ ExtKeyUsage : parsed .ExtKeyUsage ,
166+ UnknownExtKeyUsage : parsed .UnknownExtKeyUsage ,
167+ BasicConstraints : parsed .BasicConstraints ,
126168 PublicKey : cr .PublicKey ,
127169 PublicKeyAlgorithm : cr .PublicKeyAlgorithm ,
128170 Signature : cr .Signature ,
@@ -146,7 +188,7 @@ func (c *CertificateRequest) GetCertificateRequest() (*x509.CertificateRequest,
146188 SignatureAlgorithm : x509 .SignatureAlgorithm (c .SignatureAlgorithm ),
147189 }, c .Signer )
148190 if err != nil {
149- return nil , errors . Wrap ( err , "error creating certificate request" )
191+ return nil , fmt . Errorf ( "error creating certificate request: %w" , err )
150192 }
151193
152194 // If a challenge password is provided, encode and prepend it as a challenge
@@ -193,7 +235,7 @@ func (c *CertificateRequest) addChallengePassword(asn1Data []byte) ([]byte, erro
193235
194236 b , err := builder .Bytes ()
195237 if err != nil {
196- return nil , errors . Wrap ( err , "error marshaling challenge password" )
238+ return nil , fmt . Errorf ( "error marshaling challenge password: %w" , err )
197239 }
198240 challengePasswordAttr := asn1.RawValue {
199241 FullBytes : b ,
@@ -223,7 +265,7 @@ func (c *CertificateRequest) addChallengePassword(asn1Data []byte) ([]byte, erro
223265 // Marshal tbsCertificateRequest
224266 tbsCSRContents , err := asn1 .Marshal (tbsCSR )
225267 if err != nil {
226- return nil , errors . Wrap ( err , "error creating certificate request" )
268+ return nil , fmt . Errorf ( "error creating certificate request: %w" , err )
227269 }
228270 tbsCSR .Raw = tbsCSRContents
229271
@@ -239,7 +281,7 @@ func (c *CertificateRequest) addChallengePassword(asn1Data []byte) ([]byte, erro
239281 }
240282 }
241283 if ! found {
242- return nil , errors .Errorf ("error creating certificate request: unsupported signature algorithm %s " , sigAlgoOID )
284+ return nil , fmt .Errorf ("error creating certificate request: unsupported signature algorithm %q " , sigAlgoOID )
243285 }
244286
245287 // Sign tbsCertificateRequest
@@ -253,7 +295,7 @@ func (c *CertificateRequest) addChallengePassword(asn1Data []byte) ([]byte, erro
253295 var signature []byte
254296 signature , err = c .Signer .Sign (rand .Reader , signed , hashFunc )
255297 if err != nil {
256- return nil , errors . Wrap ( err , "error creating certificate request" )
298+ return nil , fmt . Errorf ( "error creating certificate request: %w" , err )
257299 }
258300
259301 // Build new certificate request and marshal
@@ -266,7 +308,7 @@ func (c *CertificateRequest) addChallengePassword(asn1Data []byte) ([]byte, erro
266308 },
267309 })
268310 if err != nil {
269- return nil , errors . Wrap ( err , "error creating certificate request" )
311+ return nil , fmt . Errorf ( "error creating certificate request: %w" , err )
270312 }
271313 return asn1Data , nil
272314}
@@ -351,7 +393,7 @@ func CreateCertificateRequest(commonName string, sans []string, signer crypto.Si
351393 URIs : uris ,
352394 }, signer )
353395 if err != nil {
354- return nil , errors . Wrap ( err , "error creating certificate request" )
396+ return nil , fmt . Errorf ( "error creating certificate request: %w" , err )
355397 }
356398 // This should not fail
357399 return x509 .ParseCertificateRequest (asn1Data )
@@ -368,3 +410,91 @@ func fixSubjectAltName(cr *x509.CertificateRequest) {
368410 }
369411 }
370412}
413+
414+ type certificateRequestParsedExtensions struct {
415+ KeyUsage KeyUsage
416+ ExtKeyUsage ExtKeyUsage
417+ UnknownExtKeyUsage UnknownExtKeyUsage
418+ BasicConstraints * BasicConstraints
419+ }
420+
421+ func parseCertificateRequestExtensions (exts []pkix.Extension ) (cr certificateRequestParsedExtensions , errs error ) {
422+ var err error
423+ for _ , ext := range exts {
424+ switch {
425+ case ext .Id .Equal (oidExtensionKeyUsage ):
426+ if cr .KeyUsage , err = parseKeyUsageExtension (ext .Value ); err != nil {
427+ errs = errors .Join (errs , err )
428+ }
429+ case ext .Id .Equal (oidExtensionExtendedKeyUsage ):
430+ if cr .ExtKeyUsage , cr .UnknownExtKeyUsage , err = parseExtKeyUsageExtension (ext .Value ); err != nil {
431+ errs = errors .Join (errs , err )
432+ }
433+ case ext .Id .Equal (oidExtensionBasicConstraints ):
434+ if cr .BasicConstraints , err = parseBasicConstraintsExtension (ext .Value ); err != nil {
435+ errs = errors .Join (errs , err )
436+ }
437+ }
438+ }
439+
440+ return
441+ }
442+
443+ func parseKeyUsageExtension (der cryptobyte.String ) (KeyUsage , error ) {
444+ var usageBits asn1.BitString
445+ if ! der .ReadASN1BitString (& usageBits ) {
446+ return 0 , errors .New ("invalid key usage" )
447+ }
448+
449+ var usage int
450+ for i := 0 ; i < 9 ; i ++ {
451+ if usageBits .At (i ) != 0 {
452+ usage |= 1 << uint (i )
453+ }
454+ }
455+
456+ return KeyUsage (usage ), nil
457+ }
458+
459+ func parseExtKeyUsageExtension (der cryptobyte.String ) (ExtKeyUsage , UnknownExtKeyUsage , error ) {
460+ var extKeyUsages ExtKeyUsage
461+ var unknownUsages UnknownExtKeyUsage
462+ if ! der .ReadASN1 (& der , cryptobyte_asn1 .SEQUENCE ) {
463+ return nil , nil , errors .New ("invalid extended key usages" )
464+ }
465+ for ! der .Empty () {
466+ var eku asn1.ObjectIdentifier
467+ if ! der .ReadASN1ObjectIdentifier (& eku ) {
468+ return nil , nil , errors .New ("invalid extended key usages" )
469+ }
470+ if extKeyUsage , ok := extKeyUsageFromOID (eku ); ok {
471+ extKeyUsages = append (extKeyUsages , extKeyUsage )
472+ } else {
473+ unknownUsages = append (unknownUsages , eku )
474+ }
475+ }
476+
477+ return extKeyUsages , unknownUsages , nil
478+ }
479+
480+ func parseBasicConstraintsExtension (der cryptobyte.String ) (* BasicConstraints , error ) {
481+ var isCA bool
482+ if ! der .ReadASN1 (& der , cryptobyte_asn1 .SEQUENCE ) {
483+ return nil , errors .New ("invalid basic constraints" )
484+ }
485+ if der .PeekASN1Tag (cryptobyte_asn1 .BOOLEAN ) {
486+ if ! der .ReadASN1Boolean (& isCA ) {
487+ return nil , errors .New ("invalid basic constraints" )
488+ }
489+ }
490+ maxPathLen := - 1
491+ if der .PeekASN1Tag (cryptobyte_asn1 .INTEGER ) {
492+ if ! der .ReadASN1Integer (& maxPathLen ) {
493+ return nil , errors .New ("invalid basic constraints" )
494+ }
495+ }
496+
497+ return & BasicConstraints {
498+ IsCA : isCA , MaxPathLen : maxPathLen ,
499+ }, nil
500+ }
0 commit comments