func marshalPublicKey(pub interface{}) (publicKeyBytes []byte, publicKeyAlgorithm pkix.AlgorithmIdentifier, err error) { switch pub := pub.(type) { case *rsa.PublicKey: publicKeyBytes, err = asn1.Marshal(rsaPublicKey{ N: pub.N, E: pub.E, }) publicKeyAlgorithm.Algorithm = oidPublicKeyRSA // This is a NULL parameters value which is technically // superfluous, but most other code includes it and, by // doing this, we match their public key hashes. publicKeyAlgorithm.Parameters = asn1.RawValue{ Tag: 5, } case *ecdsa.PublicKey: publicKeyBytes = elliptic.Marshal(pub.Curve, pub.X, pub.Y) oid, ok := oidFromNamedCurve(pub.Curve) if !ok { return nil, pkix.AlgorithmIdentifier{}, errors.New("x509: unsupported elliptic curve") } publicKeyAlgorithm.Algorithm = oidPublicKeyECDSA var paramBytes []byte paramBytes, err = asn1.Marshal(oid) if err != nil { return } publicKeyAlgorithm.Parameters.FullBytes = paramBytes default: return nil, pkix.AlgorithmIdentifier{}, errors.New("x509: only RSA and ECDSA public keys supported") } return publicKeyBytes, publicKeyAlgorithm, nil }
// MarshalPKCS1PrivateKey converts a private key to ASN.1 DER encoded form. func MarshalPKCS1PrivateKey(key *rsa.PrivateKey) []byte { key.Precompute() version := 0 if len(key.Primes) > 2 { version = 1 } priv := pkcs1PrivateKey{ Version: version, N: key.N, E: key.PublicKey.E, D: key.D, P: key.Primes[0], Q: key.Primes[1], Dp: key.Precomputed.Dp, Dq: key.Precomputed.Dq, Qinv: key.Precomputed.Qinv, } priv.AdditionalPrimes = make([]pkcs1AdditionalRSAPrime, len(key.Precomputed.CRTValues)) for i, values := range key.Precomputed.CRTValues { priv.AdditionalPrimes[i].Prime = key.Primes[2+i] priv.AdditionalPrimes[i].Exp = values.Exp priv.AdditionalPrimes[i].Coeff = values.Coeff } b, _ := asn1.Marshal(priv) return b }
func subjectBytes(cert *Certificate) ([]byte, error) { if len(cert.RawSubject) > 0 { return cert.RawSubject, nil } return asn1.Marshal(cert.Subject.ToRDNSequence()) }
// MarshalECPrivateKey marshals an EC private key into ASN.1, DER format. func MarshalECPrivateKey(key *ecdsa.PrivateKey) ([]byte, error) { oid, ok := oidFromNamedCurve(key.Curve) if !ok { return nil, errors.New("x509: unknown elliptic curve") } return asn1.Marshal(ecPrivateKey{ Version: 1, PrivateKey: key.D.Bytes(), NamedCurveOID: oid, PublicKey: asn1.BitString{Bytes: elliptic.Marshal(key.Curve, key.X, key.Y)}, }) }
// CreateCRL returns a DER encoded CRL, signed by this Certificate, that // contains the given list of revoked certificates. // // The only supported key type is RSA (*rsa.PrivateKey for priv). func (c *Certificate) CreateCRL(rand io.Reader, priv interface{}, revokedCerts []pkix.RevokedCertificate, now, expiry time.Time) (crlBytes []byte, err error) { rsaPriv, ok := priv.(*rsa.PrivateKey) if !ok { return nil, errors.New("x509: non-RSA private keys not supported") } tbsCertList := pkix.TBSCertificateList{ Version: 2, Signature: pkix.AlgorithmIdentifier{ Algorithm: oidSignatureSHA1WithRSA, }, Issuer: c.Subject.ToRDNSequence(), ThisUpdate: now.UTC(), NextUpdate: expiry.UTC(), RevokedCertificates: revokedCerts, } tbsCertListContents, err := asn1.Marshal(tbsCertList) if err != nil { return } h := sha1.New() h.Write(tbsCertListContents) digest := h.Sum(nil) signature, err := rsa.SignPKCS1v15(rand, rsaPriv, crypto.SHA1, digest) if err != nil { return } return asn1.Marshal(pkix.CertificateList{ TBSCertList: tbsCertList, SignatureAlgorithm: pkix.AlgorithmIdentifier{ Algorithm: oidSignatureSHA1WithRSA, }, SignatureValue: asn1.BitString{Bytes: signature, BitLength: len(signature) * 8}, }) }
// MarshalPKIXPublicKey serialises a public key to DER-encoded PKIX format. func MarshalPKIXPublicKey(pub interface{}) ([]byte, error) { var publicKeyBytes []byte var publicKeyAlgorithm pkix.AlgorithmIdentifier var err error if publicKeyBytes, publicKeyAlgorithm, err = marshalPublicKey(pub); err != nil { return nil, err } pkix := pkixPublicKey{ Algo: publicKeyAlgorithm, BitString: asn1.BitString{ Bytes: publicKeyBytes, BitLength: 8 * len(publicKeyBytes), }, } ret, _ := asn1.Marshal(pkix) return ret, nil }
// CreateCertificate creates a new certificate based on a template. The // following members of template are used: SerialNumber, Subject, NotBefore, // NotAfter, KeyUsage, ExtKeyUsage, UnknownExtKeyUsage, BasicConstraintsValid, // IsCA, MaxPathLen, SubjectKeyId, DNSNames, PermittedDNSDomainsCritical, // PermittedDNSDomains. // // The certificate is signed by parent. If parent is equal to template then the // certificate is self-signed. The parameter pub is the public key of the // signee and priv is the private key of the signer. // // The returned slice is the certificate in DER encoding. // // The only supported key types are RSA and ECDSA (*rsa.PublicKey or // *ecdsa.PublicKey for pub, *rsa.PrivateKey or *ecdsa.PublicKey for priv). func CreateCertificate(rand io.Reader, template, parent *Certificate, pub interface{}, priv interface{}) (cert []byte, err error) { var publicKeyBytes []byte var publicKeyAlgorithm pkix.AlgorithmIdentifier if publicKeyBytes, publicKeyAlgorithm, err = marshalPublicKey(pub); err != nil { return nil, err } var signatureAlgorithm pkix.AlgorithmIdentifier var hashFunc crypto.Hash switch priv := priv.(type) { case *rsa.PrivateKey: signatureAlgorithm.Algorithm = oidSignatureSHA1WithRSA hashFunc = crypto.SHA1 case *ecdsa.PrivateKey: switch priv.Curve { case elliptic.P224(), elliptic.P256(): hashFunc = crypto.SHA256 signatureAlgorithm.Algorithm = oidSignatureECDSAWithSHA256 case elliptic.P384(): hashFunc = crypto.SHA384 signatureAlgorithm.Algorithm = oidSignatureECDSAWithSHA384 case elliptic.P521(): hashFunc = crypto.SHA512 signatureAlgorithm.Algorithm = oidSignatureECDSAWithSHA512 default: return nil, errors.New("x509: unknown elliptic curve") } default: return nil, errors.New("x509: only RSA and ECDSA private keys supported") } if err != nil { return } if len(parent.SubjectKeyId) > 0 { template.AuthorityKeyId = parent.SubjectKeyId } extensions, err := buildExtensions(template) if err != nil { return } asn1Issuer, err := subjectBytes(parent) if err != nil { return } asn1Subject, err := subjectBytes(template) if err != nil { return } encodedPublicKey := asn1.BitString{BitLength: len(publicKeyBytes) * 8, Bytes: publicKeyBytes} c := tbsCertificate{ Version: 2, SerialNumber: template.SerialNumber, SignatureAlgorithm: signatureAlgorithm, Issuer: asn1.RawValue{FullBytes: asn1Issuer}, Validity: validity{template.NotBefore.UTC(), template.NotAfter.UTC()}, Subject: asn1.RawValue{FullBytes: asn1Subject}, PublicKey: publicKeyInfo{nil, publicKeyAlgorithm, encodedPublicKey}, Extensions: extensions, } tbsCertContents, err := asn1.Marshal(c) if err != nil { return } c.Raw = tbsCertContents h := hashFunc.New() h.Write(tbsCertContents) digest := h.Sum(nil) var signature []byte switch priv := priv.(type) { case *rsa.PrivateKey: signature, err = rsa.SignPKCS1v15(rand, priv, hashFunc, digest) case *ecdsa.PrivateKey: var r, s *big.Int if r, s, err = ecdsa.Sign(rand, priv, digest); err == nil { signature, err = asn1.Marshal(ecdsaSignature{r, s}) } default: panic("internal error") } if err != nil { return } cert, err = asn1.Marshal(certificate{ nil, c, signatureAlgorithm, asn1.BitString{Bytes: signature, BitLength: len(signature) * 8}, }) return }
func buildExtensions(template *Certificate) (ret []pkix.Extension, err error) { ret = make([]pkix.Extension, 10 /* maximum number of elements. */) n := 0 if template.KeyUsage != 0 && !oidInExtensions(oidExtensionKeyUsage, template.ExtraExtensions) { ret[n].Id = oidExtensionKeyUsage ret[n].Critical = true var a [2]byte a[0] = reverseBitsInAByte(byte(template.KeyUsage)) a[1] = reverseBitsInAByte(byte(template.KeyUsage >> 8)) l := 1 if a[1] != 0 { l = 2 } ret[n].Value, err = asn1.Marshal(asn1.BitString{Bytes: a[0:l], BitLength: l * 8}) if err != nil { return } n++ } if (len(template.ExtKeyUsage) > 0 || len(template.UnknownExtKeyUsage) > 0) && !oidInExtensions(oidExtensionExtendedKeyUsage, template.ExtraExtensions) { ret[n].Id = oidExtensionExtendedKeyUsage var oids []asn1.ObjectIdentifier for _, u := range template.ExtKeyUsage { if oid, ok := oidFromExtKeyUsage(u); ok { oids = append(oids, oid) } else { panic("internal error") } } oids = append(oids, template.UnknownExtKeyUsage...) ret[n].Value, err = asn1.Marshal(oids) if err != nil { return } n++ } if template.BasicConstraintsValid && !oidInExtensions(oidExtensionBasicConstraints, template.ExtraExtensions) { ret[n].Id = oidExtensionBasicConstraints ret[n].Value, err = asn1.Marshal(basicConstraints{template.IsCA, template.MaxPathLen}) ret[n].Critical = true if err != nil { return } n++ } if len(template.SubjectKeyId) > 0 && !oidInExtensions(oidExtensionSubjectKeyId, template.ExtraExtensions) { ret[n].Id = oidExtensionSubjectKeyId ret[n].Value, err = asn1.Marshal(template.SubjectKeyId) if err != nil { return } n++ } if len(template.AuthorityKeyId) > 0 && !oidInExtensions(oidExtensionAuthorityKeyId, template.ExtraExtensions) { ret[n].Id = oidExtensionAuthorityKeyId ret[n].Value, err = asn1.Marshal(authKeyId{template.AuthorityKeyId}) if err != nil { return } n++ } if (len(template.OCSPServer) > 0 || len(template.IssuingCertificateURL) > 0) && !oidInExtensions(oidExtensionAuthorityInfoAccess, template.ExtraExtensions) { ret[n].Id = oidExtensionAuthorityInfoAccess var aiaValues []authorityInfoAccess for _, name := range template.OCSPServer { aiaValues = append(aiaValues, authorityInfoAccess{ Method: oidAuthorityInfoAccessOcsp, Location: asn1.RawValue{Tag: 6, Class: 2, Bytes: []byte(name)}, }) } for _, name := range template.IssuingCertificateURL { aiaValues = append(aiaValues, authorityInfoAccess{ Method: oidAuthorityInfoAccessIssuers, Location: asn1.RawValue{Tag: 6, Class: 2, Bytes: []byte(name)}, }) } ret[n].Value, err = asn1.Marshal(aiaValues) if err != nil { return } n++ } if (len(template.DNSNames) > 0 || len(template.EmailAddresses) > 0 || len(template.IPAddresses) > 0) && !oidInExtensions(oidExtensionSubjectAltName, template.ExtraExtensions) { ret[n].Id = oidExtensionSubjectAltName var rawValues []asn1.RawValue for _, name := range template.DNSNames { rawValues = append(rawValues, asn1.RawValue{Tag: 2, Class: 2, Bytes: []byte(name)}) } for _, email := range template.EmailAddresses { rawValues = append(rawValues, asn1.RawValue{Tag: 1, Class: 2, Bytes: []byte(email)}) } for _, rawIP := range template.IPAddresses { // If possible, we always want to encode IPv4 addresses in 4 bytes. ip := rawIP.To4() if ip == nil { ip = rawIP } rawValues = append(rawValues, asn1.RawValue{Tag: 7, Class: 2, Bytes: ip}) } ret[n].Value, err = asn1.Marshal(rawValues) if err != nil { return } n++ } if len(template.PolicyIdentifiers) > 0 && !oidInExtensions(oidExtensionCertificatePolicies, template.ExtraExtensions) { ret[n].Id = oidExtensionCertificatePolicies policies := make([]policyInformation, len(template.PolicyIdentifiers)) for i, policy := range template.PolicyIdentifiers { policies[i].Policy = policy } ret[n].Value, err = asn1.Marshal(policies) if err != nil { return } n++ } if len(template.PermittedDNSDomains) > 0 && !oidInExtensions(oidExtensionNameConstraints, template.ExtraExtensions) { ret[n].Id = oidExtensionNameConstraints ret[n].Critical = template.PermittedDNSDomainsCritical var out nameConstraints out.Permitted = make([]generalSubtree, len(template.PermittedDNSDomains)) for i, permitted := range template.PermittedDNSDomains { out.Permitted[i] = generalSubtree{Name: permitted} } ret[n].Value, err = asn1.Marshal(out) if err != nil { return } n++ } if len(template.CRLDistributionPoints) > 0 && !oidInExtensions(oidExtensionCRLDistributionPoints, template.ExtraExtensions) { ret[n].Id = oidExtensionCRLDistributionPoints var crlDp []distributionPoint for _, name := range template.CRLDistributionPoints { rawFullName, _ := asn1.Marshal(asn1.RawValue{Tag: 6, Class: 2, Bytes: []byte(name)}) dp := distributionPoint{ DistributionPoint: distributionPointName{ FullName: asn1.RawValue{Tag: 0, Class: 2, Bytes: rawFullName}, }, } crlDp = append(crlDp, dp) } ret[n].Value, err = asn1.Marshal(crlDp) if err != nil { return } n++ } // Adding another extension here? Remember to update the maximum number // of elements in the make() at the top of the function. return append(ret[:n], template.ExtraExtensions...), nil }