diff options
Diffstat (limited to 'libgo/go/crypto/x509/x509.go')
-rw-r--r-- | libgo/go/crypto/x509/x509.go | 193 |
1 files changed, 171 insertions, 22 deletions
diff --git a/libgo/go/crypto/x509/x509.go b/libgo/go/crypto/x509/x509.go index 013f1c9..8ce57fb 100644 --- a/libgo/go/crypto/x509/x509.go +++ b/libgo/go/crypto/x509/x509.go @@ -3,10 +3,6 @@ // license that can be found in the LICENSE file. // Package x509 parses X.509-encoded keys and certificates. -// -// On UNIX systems the environment variables SSL_CERT_FILE and SSL_CERT_DIR -// can be used to override the system default locations for the SSL certificate -// file and SSL certificate files directory, respectively. package x509 import ( @@ -17,6 +13,7 @@ import ( "crypto/ed25519" "crypto/elliptic" "crypto/rsa" + "crypto/sha1" _ "crypto/sha1" _ "crypto/sha256" _ "crypto/sha512" @@ -46,6 +43,8 @@ type pkixPublicKey struct { } // ParsePKIXPublicKey parses a public key in PKIX, ASN.1 DER form. +// The encoded public key is a SubjectPublicKeyInfo structure +// (see RFC 5280, Section 4.1). // // It returns a *rsa.PublicKey, *dsa.PublicKey, *ecdsa.PublicKey, or // ed25519.PublicKey. More types might be supported in the future. @@ -106,6 +105,8 @@ func marshalPublicKey(pub interface{}) (publicKeyBytes []byte, publicKeyAlgorith } // MarshalPKIXPublicKey converts a public key to PKIX, ASN.1 DER form. +// The encoded public key is a SubjectPublicKeyInfo structure +// (see RFC 5280, Section 4.1). // // The following key types are currently supported: *rsa.PublicKey, *ecdsa.PublicKey // and ed25519.PublicKey. Unsupported key types result in an error. @@ -163,8 +164,6 @@ type dsaSignature struct { R, S *big.Int } -type ecdsaSignature dsaSignature - type validity struct { NotBefore, NotAfter time.Time } @@ -905,16 +904,7 @@ func checkSignature(algo SignatureAlgorithm, signed, signature []byte, publicKey if pubKeyAlgo != ECDSA { return signaturePublicKeyAlgoMismatchError(pubKeyAlgo, pub) } - ecdsaSig := new(ecdsaSignature) - if rest, err := asn1.Unmarshal(signature, ecdsaSig); err != nil { - return err - } else if len(rest) != 0 { - return errors.New("x509: trailing data after ECDSA signature") - } - if ecdsaSig.R.Sign() <= 0 || ecdsaSig.S.Sign() <= 0 { - return errors.New("x509: ECDSA signature contained zero or negative values") - } - if !ecdsa.Verify(pub, signed, ecdsaSig.R, ecdsaSig.S) { + if !ecdsa.VerifyASN1(pub, signed, signature) { return errors.New("x509: ECDSA verification failure") } return @@ -1374,7 +1364,7 @@ func parseCertificate(in *certificate) (*Certificate, error) { if rest, err := asn1.Unmarshal(in.TBSCertificate.Issuer.FullBytes, &issuer); err != nil { return nil, err } else if len(rest) != 0 { - return nil, errors.New("x509: trailing data after X.509 subject") + return nil, errors.New("x509: trailing data after X.509 issuer") } out.Issuer.FillFromRDNSequence(&issuer) @@ -1644,6 +1634,7 @@ var ( oidExtensionNameConstraints = []int{2, 5, 29, 30} oidExtensionCRLDistributionPoints = []int{2, 5, 29, 31} oidExtensionAuthorityInfoAccess = []int{1, 3, 6, 1, 5, 5, 7, 1, 1} + oidExtensionCRLNumber = []int{2, 5, 29, 20} ) var ( @@ -1696,7 +1687,7 @@ func isIA5String(s string) error { return nil } -func buildExtensions(template *Certificate, subjectIsEmpty bool, authorityKeyId []byte) (ret []pkix.Extension, err error) { +func buildExtensions(template *Certificate, subjectIsEmpty bool, authorityKeyId []byte, subjectKeyId []byte) (ret []pkix.Extension, err error) { ret = make([]pkix.Extension, 10 /* maximum number of elements. */) n := 0 @@ -1761,9 +1752,9 @@ func buildExtensions(template *Certificate, subjectIsEmpty bool, authorityKeyId n++ } - if len(template.SubjectKeyId) > 0 && !oidInExtensions(oidExtensionSubjectKeyId, template.ExtraExtensions) { + if len(subjectKeyId) > 0 && !oidInExtensions(oidExtensionSubjectKeyId, template.ExtraExtensions) { ret[n].Id = oidExtensionSubjectKeyId - ret[n].Value, err = asn1.Marshal(template.SubjectKeyId) + ret[n].Value, err = asn1.Marshal(subjectKeyId) if err != nil { return } @@ -2092,6 +2083,9 @@ var emptyASN1Subject = []byte{0x30, 0} // The AuthorityKeyId will be taken from the SubjectKeyId of parent, if any, // unless the resulting certificate is self-signed. Otherwise the value from // template will be used. +// +// If SubjectKeyId from template is empty and the template is a CA, SubjectKeyId +// will be generated from the hash of the public key. func CreateCertificate(rand io.Reader, template, parent *Certificate, pub, priv interface{}) (cert []byte, err error) { key, ok := priv.(crypto.Signer) if !ok { @@ -2102,6 +2096,10 @@ func CreateCertificate(rand io.Reader, template, parent *Certificate, pub, priv return nil, errors.New("x509: no SerialNumber given") } + if template.BasicConstraintsValid && !template.IsCA && template.MaxPathLen != -1 && (template.MaxPathLen != 0 || template.MaxPathLenZero) { + return nil, errors.New("x509: only CAs are allowed to specify MaxPathLen") + } + hashFunc, signatureAlgorithm, err := signingParamsForPublicKey(key.Public(), template.SignatureAlgorithm) if err != nil { return nil, err @@ -2127,7 +2125,17 @@ func CreateCertificate(rand io.Reader, template, parent *Certificate, pub, priv authorityKeyId = parent.SubjectKeyId } - extensions, err := buildExtensions(template, bytes.Equal(asn1Subject, emptyASN1Subject), authorityKeyId) + subjectKeyId := template.SubjectKeyId + if len(subjectKeyId) == 0 && template.IsCA { + // SubjectKeyId generated using method 1 in RFC 5280, Section 4.2.1.2: + // (1) The keyIdentifier is composed of the 160-bit SHA-1 hash of the + // value of the BIT STRING subjectPublicKey (excluding the tag, + // length, and number of unused bits). + h := sha1.Sum(publicKeyBytes) + subjectKeyId = h[:] + } + + extensions, err := buildExtensions(template, bytes.Equal(asn1Subject, emptyASN1Subject), authorityKeyId, subjectKeyId) if err != nil { return } @@ -2213,6 +2221,9 @@ func ParseDERCRL(derBytes []byte) (*pkix.CertificateList, error) { // CreateCRL returns a DER encoded CRL, signed by this Certificate, that // contains the given list of revoked certificates. +// +// Note: this method does not generate an RFC 5280 conformant X.509 v2 CRL. +// To generate a standards compliant CRL, use CreateRevocationList instead. func (c *Certificate) CreateCRL(rand io.Reader, priv interface{}, revokedCerts []pkix.RevokedCertificate, now, expiry time.Time) (crlBytes []byte, err error) { key, ok := priv.(crypto.Signer) if !ok { @@ -2338,7 +2349,7 @@ type certificateRequest struct { SignatureValue asn1.BitString } -// oidExtensionRequest is a PKCS#9 OBJECT IDENTIFIER that indicates requested +// oidExtensionRequest is a PKCS #9 OBJECT IDENTIFIER that indicates requested // extensions in a CSR. var oidExtensionRequest = asn1.ObjectIdentifier{1, 2, 840, 113549, 1, 9, 14} @@ -2660,3 +2671,141 @@ func parseCertificateRequest(in *certificateRequest) (*CertificateRequest, error func (c *CertificateRequest) CheckSignature() error { return checkSignature(c.SignatureAlgorithm, c.RawTBSCertificateRequest, c.Signature, c.PublicKey) } + +// RevocationList contains the fields used to create an X.509 v2 Certificate +// Revocation list with CreateRevocationList. +type RevocationList struct { + // SignatureAlgorithm is used to determine the signature algorithm to be + // used when signing the CRL. If 0 the default algorithm for the signing + // key will be used. + SignatureAlgorithm SignatureAlgorithm + + // RevokedCertificates is used to populate the revokedCertificates + // sequence in the CRL, it may be empty. RevokedCertificates may be nil, + // in which case an empty CRL will be created. + RevokedCertificates []pkix.RevokedCertificate + + // Number is used to populate the X.509 v2 cRLNumber extension in the CRL, + // which should be a monotonically increasing sequence number for a given + // CRL scope and CRL issuer. + Number *big.Int + // ThisUpdate is used to populate the thisUpdate field in the CRL, which + // indicates the issuance date of the CRL. + ThisUpdate time.Time + // NextUpdate is used to populate the nextUpdate field in the CRL, which + // indicates the date by which the next CRL will be issued. NextUpdate + // must be greater than ThisUpdate. + NextUpdate time.Time + // ExtraExtensions contains any additional extensions to add directly to + // the CRL. + ExtraExtensions []pkix.Extension +} + +// CreateRevocationList creates a new X.509 v2 Certificate Revocation List, +// according to RFC 5280, based on template. +// +// The CRL is signed by priv which should be the private key associated with +// the public key in the issuer certificate. +// +// The issuer may not be nil, and the crlSign bit must be set in KeyUsage in +// order to use it as a CRL issuer. +// +// The issuer distinguished name CRL field and authority key identifier +// extension are populated using the issuer certificate. issuer must have +// SubjectKeyId set. +func CreateRevocationList(rand io.Reader, template *RevocationList, issuer *Certificate, priv crypto.Signer) ([]byte, error) { + if template == nil { + return nil, errors.New("x509: template can not be nil") + } + if issuer == nil { + return nil, errors.New("x509: issuer can not be nil") + } + if (issuer.KeyUsage & KeyUsageCRLSign) == 0 { + return nil, errors.New("x509: issuer must have the crlSign key usage bit set") + } + if len(issuer.SubjectKeyId) == 0 { + return nil, errors.New("x509: issuer certificate doesn't contain a subject key identifier") + } + if template.NextUpdate.Before(template.ThisUpdate) { + return nil, errors.New("x509: template.ThisUpdate is after template.NextUpdate") + } + if template.Number == nil { + return nil, errors.New("x509: template contains nil Number field") + } + + hashFunc, signatureAlgorithm, err := signingParamsForPublicKey(priv.Public(), template.SignatureAlgorithm) + if err != nil { + return nil, err + } + + // Force revocation times to UTC per RFC 5280. + revokedCertsUTC := make([]pkix.RevokedCertificate, len(template.RevokedCertificates)) + for i, rc := range template.RevokedCertificates { + rc.RevocationTime = rc.RevocationTime.UTC() + revokedCertsUTC[i] = rc + } + + aki, err := asn1.Marshal(authKeyId{Id: issuer.SubjectKeyId}) + if err != nil { + return nil, err + } + crlNum, err := asn1.Marshal(template.Number) + if err != nil { + return nil, err + } + + tbsCertList := pkix.TBSCertificateList{ + Version: 1, // v2 + Signature: signatureAlgorithm, + Issuer: issuer.Subject.ToRDNSequence(), + ThisUpdate: template.ThisUpdate.UTC(), + NextUpdate: template.NextUpdate.UTC(), + Extensions: []pkix.Extension{ + { + Id: oidExtensionAuthorityKeyId, + Value: aki, + }, + { + Id: oidExtensionCRLNumber, + Value: crlNum, + }, + }, + } + if len(revokedCertsUTC) > 0 { + tbsCertList.RevokedCertificates = revokedCertsUTC + } + + if len(template.ExtraExtensions) > 0 { + tbsCertList.Extensions = append(tbsCertList.Extensions, template.ExtraExtensions...) + } + + tbsCertListContents, err := asn1.Marshal(tbsCertList) + if err != nil { + return nil, err + } + + input := tbsCertListContents + if hashFunc != 0 { + h := hashFunc.New() + h.Write(tbsCertListContents) + input = h.Sum(nil) + } + var signerOpts crypto.SignerOpts = hashFunc + if template.SignatureAlgorithm.isRSAPSS() { + signerOpts = &rsa.PSSOptions{ + SaltLength: rsa.PSSSaltLengthEqualsHash, + Hash: hashFunc, + } + } + + signature, err := priv.Sign(rand, input, signerOpts) + if err != nil { + return nil, err + } + + return asn1.Marshal(pkix.CertificateList{ + TBSCertList: tbsCertList, + SignatureAlgorithm: signatureAlgorithm, + SignatureValue: asn1.BitString{Bytes: signature, BitLength: len(signature) * 8}, + }) +} |