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.
294 lines
9.7 KiB
294 lines
9.7 KiB
package cms
|
|
|
|
import (
|
|
"bytes"
|
|
"crypto/sha256"
|
|
"errors"
|
|
"fmt"
|
|
"time"
|
|
"unicode/utf8"
|
|
|
|
"g.activething.com/go/DateKeys/internal/der"
|
|
)
|
|
|
|
// Cert is an X.509 certificate read with the profile of spec §29.10 for what
|
|
// DateKeys uses of it: who it names, when it is valid and its key. DateKeys
|
|
// does not check who issued it. It is read with the DER of this module, not
|
|
// with crypto/x509 or encoding/asn1, so that two implementations read it the
|
|
// same: a certificate with a key of a curve that Go does not have, such as
|
|
// brainpool, is still one that a signer names, and its signature is "not
|
|
// verifiable", not malformed.
|
|
type Cert struct {
|
|
// Raw is the DER of the certificate and Hash its SHA-256.
|
|
Raw []byte
|
|
Hash [32]byte
|
|
// Serial is the content of serialNumber; RawIssuer and RawSubject are the
|
|
// DER of the two names, and SKI the keyIdentifier of the extension
|
|
// subjectKeyIdentifier, nil without it.
|
|
Serial []byte
|
|
RawIssuer, RawSubject []byte
|
|
SKI []byte
|
|
NotBefore, NotAfter time.Time
|
|
// SPKI is the DER of the SubjectPublicKeyInfo.
|
|
SPKI []byte
|
|
subject, issuer []attribute
|
|
}
|
|
|
|
// attribute is an AttributeTypeAndValue of a name: the content of its object
|
|
// identifier and the DER of its value.
|
|
type attribute struct{ oid, value []byte }
|
|
|
|
var (
|
|
oidSKI = oid("2.5.29.14")
|
|
oidCommonName = oid("2.5.4.3")
|
|
oidSurname = oid("2.5.4.4")
|
|
oidOrgName = oid("2.5.4.10")
|
|
oidGivenName = oid("2.5.4.42")
|
|
)
|
|
|
|
// ParseCert reads the DER of a certificate, which its caller checked, with
|
|
// the profile of spec §29.10:
|
|
//
|
|
// - a SEQUENCE of tbsCertificate, signatureAlgorithm and a BIT STRING;
|
|
// - tbsCertificate: version [0], which is 2 (version 3), serialNumber,
|
|
// signature, issuer, validity, subject and subjectPublicKeyInfo, then
|
|
// [1], [2] and [3] when present, in that order and nothing after;
|
|
// - a name: a SEQUENCE of non-empty SETs of AttributeTypeAndValue, each an
|
|
// object identifier and one value, in any order;
|
|
// - validity: two times, UTCTime or GeneralizedTime without a fraction;
|
|
// - extensions: [3] holds a SEQUENCE of one or more Extension, each an
|
|
// object identifier, an optional BOOLEAN and an OCTET STRING, none twice;
|
|
// subjectKeyIdentifier holds a non-empty OCTET STRING.
|
|
//
|
|
// What the profile does not read decides nothing: the signature of the
|
|
// certificate, its algorithm and the other extensions.
|
|
func ParseCert(raw []byte) (*Cert, error) {
|
|
bad := func(what string) (*Cert, error) { return nil, fmt.Errorf("certificate: %s", what) }
|
|
id, top, err := der.Split(raw)
|
|
if err != nil || id != 0x30 || len(top) != 3 || top[0][0] != 0x30 || top[1][0] != 0x30 || top[2][0] != 0x03 {
|
|
return bad("not a SEQUENCE of tbsCertificate, signatureAlgorithm and signature")
|
|
}
|
|
_, f, err := der.Split(top[0])
|
|
if err != nil || len(f) < 7 || f[0][0] != 0xa0 {
|
|
return bad("a tbsCertificate without version, or with fields missing")
|
|
}
|
|
if _, v, err := der.Split(f[0]); err != nil || len(v) != 1 || !bytes.Equal(v[0], []byte{0x02, 0x01, 0x02}) {
|
|
return bad("the version is not 3")
|
|
}
|
|
f = f[1:]
|
|
if f[0][0] != 0x02 || f[1][0] != 0x30 || f[2][0] != 0x30 || f[3][0] != 0x30 || f[4][0] != 0x30 || f[5][0] != 0x30 {
|
|
return bad("the fields of tbsCertificate")
|
|
}
|
|
c := &Cert{Raw: raw, Hash: sha256.Sum256(raw), RawIssuer: f[2], RawSubject: f[4], SPKI: f[5]}
|
|
if c.Serial, err = der.Content(f[0]); err != nil {
|
|
return bad("serialNumber")
|
|
}
|
|
if c.issuer, err = parseName(f[2]); err != nil {
|
|
return bad("issuer: " + err.Error())
|
|
}
|
|
if c.subject, err = parseName(f[4]); err != nil {
|
|
return bad("subject: " + err.Error())
|
|
}
|
|
if _, v, err := der.Split(f[3]); err != nil || len(v) != 2 {
|
|
return bad("validity")
|
|
} else if c.NotBefore, err = certTime(v[0]); err != nil {
|
|
return bad("notBefore: " + err.Error())
|
|
} else if c.NotAfter, err = certTime(v[1]); err != nil {
|
|
return bad("notAfter: " + err.Error())
|
|
}
|
|
rest := f[6:]
|
|
for _, tag := range []byte{0x81, 0x82} { // issuerUniqueID, subjectUniqueID
|
|
if len(rest) > 0 && rest[0][0] == tag {
|
|
rest = rest[1:]
|
|
}
|
|
}
|
|
if len(rest) > 0 && rest[0][0] == 0xa3 {
|
|
if c.SKI, err = parseExtensions(rest[0]); err != nil {
|
|
return bad(err.Error())
|
|
}
|
|
rest = rest[1:]
|
|
}
|
|
if len(rest) != 0 {
|
|
return bad("a field out of its place, or after the last")
|
|
}
|
|
return c, nil
|
|
}
|
|
|
|
// certTime reads a time of validity: a UTCTime or a GeneralizedTime in DER,
|
|
// without a fraction of seconds (RFC 5280 4.1.2.5).
|
|
func certTime(b []byte) (time.Time, error) {
|
|
t, fraction, err := der.ParseTime(b)
|
|
if err == nil && fraction {
|
|
err = errors.New("a GeneralizedTime with a fraction of seconds")
|
|
}
|
|
return t, err
|
|
}
|
|
|
|
// parseName reads a Name: a SEQUENCE of RelativeDistinguishedName, each a
|
|
// non-empty SET of AttributeTypeAndValue. The order of a SET is not checked:
|
|
// a name only gives the text that a reader shows.
|
|
func parseName(b []byte) ([]attribute, error) {
|
|
_, rdns, err := der.Split(b)
|
|
if err != nil {
|
|
return nil, errors.New("not a SEQUENCE")
|
|
}
|
|
var out []attribute
|
|
for _, rdn := range rdns {
|
|
id, atvs, err := der.Split(rdn)
|
|
if err != nil || id != 0x31 || len(atvs) == 0 {
|
|
return nil, errors.New("a RelativeDistinguishedName that is not a non-empty SET")
|
|
}
|
|
for _, atv := range atvs {
|
|
id, p, err := der.Split(atv)
|
|
if err != nil || id != 0x30 || len(p) != 2 || p[0][0] != 0x06 {
|
|
return nil, errors.New("an AttributeTypeAndValue that is not an object identifier and a value")
|
|
}
|
|
o, _ := der.Content(p[0])
|
|
out = append(out, attribute{o, p[1]})
|
|
}
|
|
}
|
|
return out, nil
|
|
}
|
|
|
|
// parseExtensions reads [3] of tbsCertificate and returns the keyIdentifier
|
|
// of subjectKeyIdentifier, nil without it.
|
|
func parseExtensions(b []byte) ([]byte, error) {
|
|
_, in, err := der.Split(b)
|
|
if err != nil || len(in) != 1 || in[0][0] != 0x30 {
|
|
return nil, errors.New("extensions")
|
|
}
|
|
_, exts, err := der.Split(in[0])
|
|
if err != nil || len(exts) == 0 {
|
|
return nil, errors.New("extensions without an Extension")
|
|
}
|
|
seen := map[string]bool{}
|
|
var ski []byte
|
|
for _, e := range exts {
|
|
id, p, err := der.Split(e)
|
|
if err != nil || id != 0x30 || len(p) < 2 || len(p) > 3 || p[0][0] != 0x06 || p[len(p)-1][0] != 0x04 || len(p) == 3 && p[1][0] != 0x01 {
|
|
return nil, errors.New("an Extension that is not an object identifier, an optional BOOLEAN and an OCTET STRING")
|
|
}
|
|
o, _ := der.Content(p[0])
|
|
if seen[string(o)] {
|
|
return nil, errors.New("an extension twice")
|
|
}
|
|
seen[string(o)] = true
|
|
if bytes.Equal(o, oidSKI) {
|
|
v, _ := der.Content(p[len(p)-1])
|
|
if der.Check(v) != nil || v[0] != 0x04 {
|
|
return nil, errors.New("a subjectKeyIdentifier that is not an OCTET STRING")
|
|
}
|
|
if ski, _ = der.Content(v); len(ski) == 0 {
|
|
return nil, errors.New("an empty subjectKeyIdentifier")
|
|
}
|
|
}
|
|
}
|
|
return ski, nil
|
|
}
|
|
|
|
// text returns the text of the value of an attribute of a name, and false
|
|
// when it is not of a string type that the profile reads, or when its bytes
|
|
// break its type (spec §29.10): UTF8String in valid UTF-8, PrintableString
|
|
// in its alphabet, IA5String and TeletexString in ASCII, and BMPString in
|
|
// UTF-16BE without surrogates. Nothing is removed from the text: a byte order
|
|
// mark or a terminator stays, and the rules of §29.6 decide.
|
|
func text(v []byte) (string, bool) {
|
|
c, err := der.Content(v)
|
|
if err != nil {
|
|
return "", false
|
|
}
|
|
switch v[0] {
|
|
case 0x0c: // UTF8String
|
|
return string(c), utf8.Valid(c)
|
|
case 0x13: // PrintableString
|
|
for _, b := range c {
|
|
if !printable(b) {
|
|
return "", false
|
|
}
|
|
}
|
|
case 0x14, 0x16: // TeletexString, IA5String
|
|
for _, b := range c {
|
|
if b > 0x7f {
|
|
return "", false
|
|
}
|
|
}
|
|
case 0x1e: // BMPString
|
|
if len(c)%2 != 0 {
|
|
return "", false
|
|
}
|
|
r := make([]rune, 0, len(c)/2)
|
|
for i := 0; i < len(c); i += 2 {
|
|
u := rune(c[i])<<8 | rune(c[i+1])
|
|
if u >= 0xd800 && u <= 0xdfff {
|
|
return "", false
|
|
}
|
|
r = append(r, u)
|
|
}
|
|
return string(r), true
|
|
default:
|
|
return "", false
|
|
}
|
|
return string(c), true
|
|
}
|
|
|
|
// printable reports whether b is in the alphabet of PrintableString (X.680).
|
|
func printable(b byte) bool {
|
|
return b >= 'a' && b <= 'z' || b >= 'A' && b <= 'Z' || b >= '0' && b <= '9' || bytes.IndexByte([]byte(" '()+,-./:=?"), b) >= 0
|
|
}
|
|
|
|
// nameText returns the text of the only attribute of type o among attrs, and
|
|
// false when there is none, when there are several, or when its value is not
|
|
// text.
|
|
func nameText(attrs []attribute, o []byte) (string, bool) {
|
|
var v []byte
|
|
n := 0
|
|
for _, a := range attrs {
|
|
if bytes.Equal(a.oid, o) {
|
|
v, n = a.value, n+1
|
|
}
|
|
}
|
|
if n != 1 {
|
|
return "", false
|
|
}
|
|
return text(v)
|
|
}
|
|
|
|
// Holder returns the name of the subject as spec §29.7 takes it: its
|
|
// givenName and its surname, when it has one of each, and its commonName
|
|
// otherwise; "" when it has neither. The commonName comes second because it
|
|
// may carry the national identifier of the person, as the one of the FNMT
|
|
// does. The caller applies the rules of text of §29.6, and shows the hash of
|
|
// the certificate when they fail.
|
|
func (c *Cert) Holder() string {
|
|
given, ok1 := nameText(c.subject, oidGivenName)
|
|
sur, ok2 := nameText(c.subject, oidSurname)
|
|
if ok1 && ok2 && given != "" && sur != "" {
|
|
return given + " " + sur
|
|
}
|
|
if cn, ok := nameText(c.subject, oidCommonName); ok {
|
|
return cn
|
|
}
|
|
return ""
|
|
}
|
|
|
|
// IssuerName returns the issuer that the certificate names: its commonName,
|
|
// or its organizationName, or "" when it has neither (spec §29.7).
|
|
func (c *Cert) IssuerName() string {
|
|
if cn, ok := nameText(c.issuer, oidCommonName); ok {
|
|
return cn
|
|
}
|
|
if o, ok := nameText(c.issuer, oidOrgName); ok {
|
|
return o
|
|
}
|
|
return ""
|
|
}
|
|
|
|
// ValidAt reports whether t is in the validity period of the certificate.
|
|
func (c *Cert) ValidAt(t time.Time) bool {
|
|
return !t.Before(c.NotBefore) && !t.After(c.NotAfter)
|
|
}
|
|
|
|
func (c *Cert) hasSID(issuer, serial []byte) bool {
|
|
return bytes.Equal(c.RawIssuer, issuer) && bytes.Equal(c.Serial, serial)
|
|
}
|