package cmstest import ( "crypto" "crypto/ecdsa" "crypto/elliptic" "crypto/rand" "crypto/rsa" "crypto/sha256" "crypto/x509" "encoding/asn1" "math/big" "time" "unicode/utf16" ) // CertSpec describes a certificate that NewCert writes field by field, from // the DER of its tbsCertificate, to write what crypto/x509 does not let one // write: names of any string type with any bytes, an attribute twice or none, // no version, times with a fraction, an extension twice, a compressed key or // an even modulus, and any signature, which DateKeys does not check (spec // §29.10). Each field holds the DER of its element as it goes in the // certificate; nil takes the default of a certificate of version 3 of the key. type CertSpec struct { // CN names the subject, CN = CN in a UTF8String, when Subject is nil. CN string // From and To are the validity, 2020-01-01 to 2040-01-01 by default, // written as RFC 5280 does when NotBefore and NotAfter are nil. From, To time.Time // Version is the field [0] EXPLICIT of the version, INTEGER 2 (version // 3) by default; NoVersion leaves it out, as a version 1 certificate. Version []byte NoVersion bool // Serial is the serialNumber, a random positive INTEGER by default. Serial []byte // SigAlg is the AlgorithmIdentifier of the signature, in tbsCertificate // and after it: that of the key with SHA-256 by default. SigAlg []byte // Issuer and Subject are the names; the issuer is the subject by default, // as in a self-signed certificate. Issuer, Subject []byte // NotBefore and NotAfter are the times of validity as written. NotBefore, NotAfter []byte // SPKI is the SubjectPublicKeyInfo, that of the key by default. SPKI []byte // UniqueIDs are written after the SPKI: [1] issuerUniqueID and [2] // subjectUniqueID. UniqueIDs [][]byte // SKI is the keyIdentifier of the extension subjectKeyIdentifier of the // default extensions, and what a sid by subjectKeyIdentifier names: 20 // bytes of the hash of the SPKI by default. SKI []byte // Extensions are the Extension elements of [3]: subjectKeyIdentifier and // keyUsage by default. An empty, non-nil slice writes [3] with an empty // SEQUENCE, and NoExtensions writes no [3]. Extensions [][]byte NoExtensions bool // After are elements written at the end of tbsCertificate. After [][]byte // Signature is the BIT STRING of the signature as written; by default // the key signs tbsCertificate. Signature []byte } // NewCert returns a signer of key whose certificate is the one that spec // describes. func NewCert(spec CertSpec, key crypto.Signer) Signer { from, to := spec.From, spec.To if from.IsZero() { from = time.Date(2020, 1, 1, 0, 0, 0, 0, time.UTC) } if to.IsZero() { to = time.Date(2040, 1, 1, 0, 0, 0, 0, time.UTC) } serial := spec.Serial if serial == nil { n, err := rand.Int(rand.Reader, big.NewInt(1<<62)) if err != nil { panic(err) } serial = BigInt(n.Add(n, big.NewInt(1))) } sigAlg := spec.SigAlg if sigAlg == nil { sigAlg = AlgID(OIDECDSA256) if _, ok := key.(*rsa.PrivateKey); ok { sigAlg = AlgID(OIDSHA256RSA, Null()) } } subject := spec.Subject if subject == nil { cn := spec.CN if cn == "" { cn = "DateKeys test" } subject = Name(ATV(OIDCommonName, UTF8(cn))) } issuer := spec.Issuer if issuer == nil { issuer = subject } notBefore, notAfter := spec.NotBefore, spec.NotAfter if notBefore == nil { notBefore = CertTimeOf(from) } if notAfter == nil { notAfter = CertTimeOf(to) } spki := spec.SPKI if spki == nil { spki = SPKI(key.Public()) } ski := spec.SKI if ski == nil { h := sha256.Sum256(spki) ski = h[:20] } var tbs [][]byte if !spec.NoVersion { version := spec.Version if version == nil { version = tlv(0xa0, Int(2)) } tbs = append(tbs, version) } tbs = append(tbs, serial, sigAlg, issuer, Seq(notBefore, notAfter), subject, spki) tbs = append(tbs, spec.UniqueIDs...) if !spec.NoExtensions { exts := spec.Extensions if exts == nil { exts = [][]byte{ExtSKI(ski), ExtKeyUsage()} } tbs = append(tbs, tlv(0xa3, Seq(exts...))) } tbsDER := Seq(append(tbs, spec.After...)...) signature := spec.Signature if signature == nil { _, sig := sign(key, Options{Hash: crypto.SHA256}, sum(crypto.SHA256, tbsDER)) signature = BitString(sig) } c := &Cert{Raw: Seq(tbsDER, sigAlg, signature), RawIssuer: issuer, Serial: serial} if spec.Extensions == nil && !spec.NoExtensions || spec.SKI != nil { c.SubjectKeyId = ski } return Signer{Cert: c, Key: key} } // The attribute types of a name. var ( OIDCommonName = asn1.ObjectIdentifier{2, 5, 4, 3} OIDSurname = asn1.ObjectIdentifier{2, 5, 4, 4} OIDSerialNumber = asn1.ObjectIdentifier{2, 5, 4, 5} OIDCountry = asn1.ObjectIdentifier{2, 5, 4, 6} OIDOrganization = asn1.ObjectIdentifier{2, 5, 4, 10} OIDOrgUnit = asn1.ObjectIdentifier{2, 5, 4, 11} OIDGivenName = asn1.ObjectIdentifier{2, 5, 4, 42} OIDSKI = asn1.ObjectIdentifier{2, 5, 29, 14} OIDKeyUsage = asn1.ObjectIdentifier{2, 5, 29, 15} ) // Name is a Name with one RelativeDistinguishedName for each attribute, in // the order given. func Name(atvs ...[]byte) []byte { rdns := make([][]byte, len(atvs)) for i, a := range atvs { rdns[i] = tlv(0x31, a) } return Seq(rdns...) } // RDN is a RelativeDistinguishedName of several attributes, in the order // given, for NameOf. func RDN(atvs ...[]byte) []byte { return tlv(0x31, atvs...) } // NameOf is a Name of the RelativeDistinguishedName elements given. func NameOf(rdns ...[]byte) []byte { return Seq(rdns...) } // ATV is an AttributeTypeAndValue. func ATV(oid asn1.ObjectIdentifier, value []byte) []byte { return Seq(OID(oid), value) } // The string types of a name, with the bytes as given: those that break // their type too. // UTF8 is a UTF8String. func UTF8(s string) []byte { return tlv(0x0c, []byte(s)) } // Numeric is a NumericString. func Numeric(s string) []byte { return tlv(0x12, []byte(s)) } // Printable is a PrintableString. func Printable(s string) []byte { return tlv(0x13, []byte(s)) } // Teletex is a TeletexString. func Teletex(s string) []byte { return tlv(0x14, []byte(s)) } // IA5 is an IA5String. func IA5(s string) []byte { return tlv(0x16, []byte(s)) } // Visible is a VisibleString. func Visible(s string) []byte { return tlv(0x1a, []byte(s)) } // BMP is a BMPString with the bytes as given: of odd length, or with a // surrogate. func BMP(b []byte) []byte { return tlv(0x1e, b) } // BMPText is the BMPString of s in UTF-16BE; a code point outside the BMP // becomes a surrogate pair. func BMPText(s string) []byte { var b []byte for _, u := range utf16.Encode([]rune(s)) { b = append(b, byte(u>>8), byte(u)) } return BMP(b) } // Extension is an Extension, with critical only when it is true, as DER // writes it. func Extension(oid asn1.ObjectIdentifier, critical bool, value []byte) []byte { f := [][]byte{OID(oid)} if critical { f = append(f, Bool(true)) } return Seq(append(f, Octets(value))...) } // ExtSKI is the extension subjectKeyIdentifier with the keyIdentifier id. func ExtSKI(id []byte) []byte { return Extension(OIDSKI, false, Octets(id)) } // ExtKeyUsage is the extension keyUsage with digitalSignature. func ExtKeyUsage() []byte { return Extension(OIDKeyUsage, true, []byte{0x03, 0x02, 0x07, 0x80}) } // SPKI is the SubjectPublicKeyInfo of a public key, as crypto/x509 writes it: // an EC point uncompressed, and RSA with NULL parameters. func SPKI(pub crypto.PublicKey) []byte { b, err := x509.MarshalPKIXPublicKey(pub) if err != nil { panic(err) } return b } // CurveOID returns the named curve of curve: P-256, P-384 or P-521. func CurveOID(curve elliptic.Curve) asn1.ObjectIdentifier { switch curve { case elliptic.P384(): return OIDP384 case elliptic.P521(): return OIDP521 } return OIDP256 } // Uncompressed returns the point of pub, uncompressed. func Uncompressed(pub *ecdsa.PublicKey) []byte { b, err := pub.Bytes() if err != nil { panic(err) } return b } // Compressed returns the point of pub, compressed (SEC 1 2.3.3). func Compressed(pub *ecdsa.PublicKey) []byte { u := Uncompressed(pub) n := (len(u) - 1) / 2 return append([]byte{2 | u[len(u)-1]&1}, u[1:1+n]...) } // SPKIEC is the SubjectPublicKeyInfo of id-ecPublicKey with the parameters // and the point given. func SPKIEC(params, point []byte) []byte { return Seq(AlgID(OIDECPublicKey, params), BitString(point)) } // SPKICompressed is the SubjectPublicKeyInfo of pub with its point // compressed, which the table of spec §29.10 does not have. func SPKICompressed(pub *ecdsa.PublicKey) []byte { return SPKIEC(OID(CurveOID(pub.Curve)), Compressed(pub)) } // SPKIRSA is the SubjectPublicKeyInfo of rsaEncryption with NULL parameters // and the modulus and exponent given: an even modulus, or a size outside the // table. func SPKIRSA(n, e *big.Int) []byte { return Seq(AlgID(OIDRSA, Null()), BitString(Seq(BigInt(n), BigInt(e)))) }