You can not select more than 25 topics Topics must start with a letter or number, can include dashes ('-') and can be up to 35 characters long.
DateKeys/internal/cms/cmstest/cert.go

288 lines
8.8 KiB

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))))
}

Powered by TurnKey Linux.