CMS reader: its own certificate profile, identifiers by their bytes

Fixes of the review of the session of 1 and 2 October in internal/cms and
internal/der:

- Object identifiers are compared by the bytes of their DER: an arc of 2^31
  or more no longer makes an attribute that decides nothing fail the
  signature (F1), and an algorithm with one is outside the table (F5, S1),
  as spec v0.11 says.
- A SET OF may repeat an element, as X.690 allows: a TSA that sends its
  certificate twice no longer gives S2. Two copies of a certificate are one.
- Certificates are read with a profile of their own instead of
  encoding/asn1 and crypto/x509, field by field, so that a second
  implementation can read them the same: version 3, the fields in order,
  names of non-empty SETs, times of validity in DER without a fraction,
  extensions without repetition, and the text of a name only from
  UTF8String, PrintableString, IA5String, TeletexString in ASCII and
  BMPString without surrogates, nothing removed from it. A certificate that
  breaks the profile decides nothing unless a SignerInfo names it. The
  holder is givenName and surname before commonName, which in the
  certificates of the FNMT carries the NIF; the issuer is its commonName or
  its organizationName.
- The key: RSA with NULL parameters, exactly a modulus and an exponent, the
  modulus odd; EC only uncompressed on P-256, P-384 and P-521.
- A key of another scheme than its algorithm is invalid (F2) and not
  outside the table (F5), as step 3 of 29.10 says; a messageImprint of
  another length is S3; the crls of a token decide nothing.
- DER: UTCTime and GeneralizedTime in their forms of X.690, a date that
  exists, and the millis and micros of accuracy as minimal INTEGERs.

Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
v0.12
dev 6 days ago
parent fee531b768
commit 839e1173e0

@ -3,136 +3,284 @@ package cms
import (
"bytes"
"crypto/sha256"
"crypto/x509/pkix"
"encoding/asn1"
"errors"
"fmt"
"math/big"
"strings"
"time"
"unicode/utf8"
"g.activething.com/go/DateKeys/internal/der"
)
// Cert is an X.509 certificate read for what spec v0.11 §29.10 uses of it:
// who it names, when it is valid and its key. DateKeys does not check who
// issued it. It is read with encoding/asn1 and not with crypto/x509, which
// refuses a certificate with a key of a curve that Go does not have, such as
// brainpool: that certificate is still one that a signer names, and its
// signature is "not verifiable", not malformed.
// 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 *big.Int
// 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 pkix.RDNSequence
Issuer pkix.RDNSequence
subject, issuer []attribute
}
type tbsCertificate struct {
Raw asn1.RawContent
Version int `asn1:"optional,explicit,default:0,tag:0"`
Serial *big.Int
SigAlg asn1.RawValue
Issuer asn1.RawValue
Validity validity
Subject asn1.RawValue
PublicKey asn1.RawValue
IssuerUID asn1.BitString `asn1:"optional,tag:1"`
SubjectUID asn1.BitString `asn1:"optional,tag:2"`
Extensions []pkix.Extension `asn1:"optional,explicit,tag:3"`
}
// 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 }
type validity struct{ NotBefore, NotAfter time.Time }
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")
)
type certificate struct {
TBS tbsCertificate
SigAlg asn1.RawValue
Sig asn1.BitString
// 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
}
var oidSKI = asn1.ObjectIdentifier{2, 5, 29, 14}
// 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
}
// ParseCert reads the DER of a certificate.
func ParseCert(raw []byte) (*Cert, error) {
var c certificate
rest, err := asn1.Unmarshal(raw, &c)
// 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, fmt.Errorf("certificate: %w", err)
return nil, errors.New("not a SEQUENCE")
}
if len(rest) != 0 {
return nil, errors.New("certificate: bytes after it")
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")
}
t := &c.TBS
if t.Serial == nil || t.Issuer.Tag != asn1.TagSequence || t.Subject.Tag != asn1.TagSequence || t.PublicKey.Tag != asn1.TagSequence {
return nil, errors.New("certificate: malformed")
o, _ := der.Content(p[0])
out = append(out, attribute{o, p[1]})
}
out := &Cert{
Raw: raw, Hash: sha256.Sum256(raw), Serial: t.Serial,
RawIssuer: t.Issuer.FullBytes, RawSubject: t.Subject.FullBytes,
NotBefore: t.Validity.NotBefore, NotAfter: t.Validity.NotAfter, SPKI: t.PublicKey.FullBytes,
}
if _, err := asn1.Unmarshal(out.RawSubject, &out.Subject); err != nil {
return nil, fmt.Errorf("certificate: subject: %w", err)
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")
}
if _, err := asn1.Unmarshal(out.RawIssuer, &out.Issuer); err != nil {
return nil, fmt.Errorf("certificate: issuer: %w", err)
_, exts, err := der.Split(in[0])
if err != nil || len(exts) == 0 {
return nil, errors.New("extensions without an Extension")
}
for _, e := range t.Extensions {
if e.Id.Equal(oidSKI) {
seen := map[string]bool{}
var ski []byte
if rest, err := asn1.Unmarshal(e.Value, &ski); err != nil || len(rest) != 0 {
return nil, errors.New("certificate: subjectKeyIdentifier malformed")
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")
}
out.SKI = ski
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")
}
return out, nil
if ski, _ = der.Content(v); len(ski) == 0 {
return nil, errors.New("an empty subjectKeyIdentifier")
}
}
}
return ski, nil
}
var (
oidCommonName = asn1.ObjectIdentifier{2, 5, 4, 3}
oidSurname = asn1.ObjectIdentifier{2, 5, 4, 4}
oidGivenName = asn1.ObjectIdentifier{2, 5, 4, 42}
)
// 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
}
func rdnString(rdn pkix.RDNSequence, oid asn1.ObjectIdentifier) string {
for _, set := range rdn {
for _, a := range set {
if s, ok := a.Value.(string); ok && a.Type.Equal(oid) {
return s
// 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 ""
return text(v)
}
// Holder returns the name of the subject, taken from its commonName or from
// its givenName and surname, and "" when it has neither. It does not apply the
// rules of text of spec §29.6 to it: the caller does, and shows the hash of
// 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 {
if n := rdnString(c.Subject, oidCommonName); n != "" {
return n
}
given, sur := rdnString(c.Subject, oidGivenName), rdnString(c.Subject, oidSurname)
if given != "" && sur != "" {
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 as the certificate names it, as a text for
// the person to read: commonName, or all of the attributes it has.
// 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 n := rdnString(c.Issuer, oidCommonName); n != "" {
return n
if cn, ok := nameText(c.issuer, oidCommonName); ok {
return cn
}
if o, ok := nameText(c.issuer, oidOrgName); ok {
return o
}
return strings.TrimSpace(c.Issuer.String())
return ""
}
// ValidAt reports whether t is in the validity period of the certificate.
@ -140,6 +288,6 @@ func (c *Cert) ValidAt(t time.Time) bool {
return !t.Before(c.NotBefore) && !t.After(c.NotAfter)
}
func (c *Cert) hasSID(issuer []byte, serial *big.Int) bool {
return bytes.Equal(c.RawIssuer, issuer) && c.Serial.Cmp(serial) == 0
func (c *Cert) hasSID(issuer, serial []byte) bool {
return bytes.Equal(c.RawIssuer, issuer) && bytes.Equal(c.Serial, serial)
}

@ -1,11 +1,13 @@
// Package cms reads the CMS signatures (RFC 5652) and the RFC 3161 time-stamp
// tokens that spec v0.11 §29.10 and §29.11 define, with the CAdES profile
// that AutoFirma and other signing applications produce, and checks them with
// a closed table of algorithms. It uses the standard library only.
// tokens that spec §29.10 and §29.11 define, with the CAdES profile that
// AutoFirma and other signing applications produce, and checks them with a
// closed table of algorithms. It uses the standard library only.
//
// It checks the signature and the dates, never who issued a certificate or
// whether it was revoked: a validator of the country that corresponds does
// that (spec §29.10).
// that (spec §29.10). Object identifiers are compared by the bytes of their
// DER, so that an arc of any size is only an identifier that the table does
// not have.
package cms
import (
@ -13,11 +15,11 @@ import (
"crypto/sha1"
"crypto/sha256"
"crypto/sha512"
"encoding/asn1"
"errors"
"fmt"
"hash"
"math/big"
"strconv"
"strings"
"g.activething.com/go/DateKeys/internal/der"
)
@ -34,26 +36,66 @@ func formErr(format string, args ...any) error {
return fmt.Errorf("%w: %s", ErrForm, fmt.Sprintf(format, args...))
}
// oid returns the content of the DER of the object identifier s, written
// with dots: the bytes that this package compares.
func oid(s string) []byte {
parts := strings.Split(s, ".")
arcs := make([]uint64, len(parts))
for i, p := range parts {
n, err := strconv.ParseUint(p, 10, 64)
if err != nil || len(parts) < 2 {
panic("cms: a bad object identifier " + s)
}
arcs[i] = n
}
out := base128(nil, arcs[0]*40+arcs[1])
for _, a := range arcs[2:] {
out = base128(out, a)
}
return out
}
func base128(out []byte, v uint64) []byte {
var tmp [10]byte
i := len(tmp) - 1
tmp[i] = byte(v & 0x7f)
for v >>= 7; v > 0; v >>= 7 {
i--
tmp[i] = byte(v&0x7f) | 0x80
}
return append(out, tmp[i:]...)
}
// oidOf returns the content of the object identifier element b.
func oidOf(b []byte) ([]byte, bool) {
if len(b) == 0 || b[0] != 0x06 {
return nil, false
}
c, err := der.Content(b)
return c, err == nil
}
// The object identifiers of the profile.
var (
oidData = asn1.ObjectIdentifier{1, 2, 840, 113549, 1, 7, 1}
oidSignedData = asn1.ObjectIdentifier{1, 2, 840, 113549, 1, 7, 2}
oidContentType = asn1.ObjectIdentifier{1, 2, 840, 113549, 1, 9, 3}
oidMessageDig = asn1.ObjectIdentifier{1, 2, 840, 113549, 1, 9, 4}
oidSigCertV1 = asn1.ObjectIdentifier{1, 2, 840, 113549, 1, 9, 16, 2, 12}
oidSigCertV2 = asn1.ObjectIdentifier{1, 2, 840, 113549, 1, 9, 16, 2, 47}
oidSigTimeStamp = asn1.ObjectIdentifier{1, 2, 840, 113549, 1, 9, 16, 2, 14}
oidTSTInfo = asn1.ObjectIdentifier{1, 2, 840, 113549, 1, 9, 16, 1, 4}
oidRIOCSP = asn1.ObjectIdentifier{1, 3, 6, 1, 5, 5, 7, 16, 2}
oidData = oid("1.2.840.113549.1.7.1")
oidSignedData = oid("1.2.840.113549.1.7.2")
oidContentType = oid("1.2.840.113549.1.9.3")
oidMessageDig = oid("1.2.840.113549.1.9.4")
oidSigCertV1 = oid("1.2.840.113549.1.9.16.2.12")
oidSigCertV2 = oid("1.2.840.113549.1.9.16.2.47")
oidSigTimeStamp = oid("1.2.840.113549.1.9.16.2.14")
oidTSTInfo = oid("1.2.840.113549.1.9.16.1.4")
oidRIOCSP = oid("1.3.6.1.5.5.7.16.2")
oidSHA1 = asn1.ObjectIdentifier{1, 3, 14, 3, 2, 26}
oidSHA256 = asn1.ObjectIdentifier{2, 16, 840, 1, 101, 3, 4, 2, 1}
oidSHA384 = asn1.ObjectIdentifier{2, 16, 840, 1, 101, 3, 4, 2, 2}
oidSHA512 = asn1.ObjectIdentifier{2, 16, 840, 1, 101, 3, 4, 2, 3}
oidSHA256 = oid("2.16.840.1.101.3.4.2.1")
oidSHA384 = oid("2.16.840.1.101.3.4.2.2")
oidSHA512 = oid("2.16.840.1.101.3.4.2.3")
)
// SignedData is the part of a CMS SignedData that the profile uses.
type SignedData struct {
// Certs are the certificates that meet the profile of §29.10, each once:
// another one decides nothing, unless a SignerInfo names it.
Certs []*Cert
// OCSP are the OCSP responses of crls.
OCSP [][]byte
@ -79,18 +121,19 @@ type SignerInfo struct {
}
type algID struct {
OID asn1.ObjectIdentifier
OID []byte // the content of the object identifier
Params []byte // the DER of the parameters, nil when absent
}
func parseAlgID(b []byte) (algID, error) {
id, kids, err := der.Split(b)
if err != nil || id != 0x30 || len(kids) < 1 || len(kids) > 2 || kids[0][0] != 0x06 {
if err != nil || id != 0x30 || len(kids) < 1 || len(kids) > 2 {
return algID{}, formErr("an AlgorithmIdentifier")
}
var a algID
if _, err := asn1.Unmarshal(kids[0], &a.OID); err != nil {
return algID{}, formErr("an AlgorithmIdentifier: %v", err)
var ok bool
if a.OID, ok = oidOf(kids[0]); !ok {
return algID{}, formErr("an AlgorithmIdentifier without an object identifier")
}
if len(kids) == 2 {
a.Params = kids[1]
@ -105,11 +148,11 @@ func (a algID) hashOf() (func() hash.Hash, bool) {
return nil, false
}
switch {
case a.OID.Equal(oidSHA256):
case bytes.Equal(a.OID, oidSHA256):
return sha256.New, true
case a.OID.Equal(oidSHA384):
case bytes.Equal(a.OID, oidSHA384):
return sha512.New384, true
case a.OID.Equal(oidSHA512):
case bytes.Equal(a.OID, oidSHA512):
return sha512.New, true
}
return nil, false
@ -126,11 +169,10 @@ func parse(b []byte, token bool) (*SignedData, error) {
return nil, formErr("%v", err)
}
id, ci, err := der.Split(b)
if err != nil || id != 0x30 || len(ci) != 2 || ci[0][0] != 0x06 || ci[1][0] != 0xa0 {
if err != nil || id != 0x30 || len(ci) != 2 || ci[1][0] != 0xa0 {
return nil, formErr("a ContentInfo")
}
var oid asn1.ObjectIdentifier
if _, err := asn1.Unmarshal(ci[0], &oid); err != nil || !oid.Equal(oidSignedData) {
if ct, ok := oidOf(ci[0]); !ok || !bytes.Equal(ct, oidSignedData) {
return nil, formErr("the content type is not id-signedData")
}
_, inner, err := der.Split(ci[1])
@ -163,7 +205,7 @@ func parse(b []byte, token bool) (*SignedData, error) {
rest = rest[1:]
}
if len(rest) > 0 && rest[0][0] == 0xa1 {
if err := parseCRLs(rest[0], out); err != nil {
if err := parseCRLs(rest[0], token, out); err != nil {
return nil, err
}
rest = rest[1:]
@ -197,20 +239,20 @@ func parse(b []byte, token bool) (*SignedData, error) {
// signature, and id-ct-TSTInfo with its content in a token.
func parseEncap(b []byte, token bool, out *SignedData) error {
_, kids, err := der.Split(b)
if err != nil || len(kids) < 1 || len(kids) > 2 || kids[0][0] != 0x06 {
if err != nil || len(kids) < 1 || len(kids) > 2 {
return formErr("encapContentInfo")
}
var oid asn1.ObjectIdentifier
if _, err := asn1.Unmarshal(kids[0], &oid); err != nil {
ct, ok := oidOf(kids[0])
if !ok {
return formErr("encapContentInfo")
}
if !token {
if !oid.Equal(oidData) || len(kids) != 1 {
if !bytes.Equal(ct, oidData) || len(kids) != 1 {
return formErr("a signature is detached: id-data and no eContent")
}
return nil
}
if !oid.Equal(oidTSTInfo) || len(kids) != 2 || kids[1][0] != 0xa0 {
if !bytes.Equal(ct, oidTSTInfo) || len(kids) != 2 || kids[1][0] != 0xa0 {
return formErr("a token holds a TSTInfo")
}
_, e, err := der.Split(kids[1])
@ -223,42 +265,51 @@ func parseEncap(b []byte, token bool, out *SignedData) error {
return nil
}
// parseCerts reads certificates. A certificate that breaks the profile of
// §29.10 decides nothing, as one that no SignerInfo names: an intermediate of
// another form is not a reason to refuse a signature, and the sid of a signer
// whose certificate breaks it names none. Two copies of a certificate are one.
func parseCerts(b []byte, out *SignedData) error {
_, kids, err := der.Split(b)
if err != nil || !der.SetOfSorted(kids) {
return formErr("certificates is not a SET OF in DER order")
}
for _, k := range kids {
for i, k := range kids {
if k[0] >= 0xa0 && k[0] <= 0xa3 { // another choice of CertificateChoices: it decides nothing
continue
}
if k[0] != 0x30 {
return formErr("a CertificateChoice that is neither a certificate nor one of the other four choices")
}
c, err := ParseCert(k)
if err != nil {
return formErr("%v", err)
if i > 0 && bytes.Equal(kids[i-1], k) {
continue
}
if c, err := ParseCert(k); err == nil {
out.Certs = append(out.Certs, c)
}
}
return nil
}
func parseCRLs(b []byte, out *SignedData) error {
// parseCRLs reads crls: in a signature, only OCSP responses (spec §29.10 rule
// 3); in a token, whatever it holds decides nothing (§29.11).
func parseCRLs(b []byte, token bool, out *SignedData) error {
_, kids, err := der.Split(b)
if err != nil || !der.SetOfSorted(kids) {
return formErr("crls is not a SET OF in DER order")
}
if token {
return nil
}
for _, k := range kids {
if k[0] != 0xa1 {
return formErr("crls holds only OCSP responses")
}
_, f, err := der.Split(k)
if err != nil || len(f) != 2 || f[0][0] != 0x06 {
if err != nil || len(f) != 2 {
return formErr("an OtherRevocationInfoFormat")
}
var oid asn1.ObjectIdentifier
if _, err := asn1.Unmarshal(f[0], &oid); err != nil || !oid.Equal(oidRIOCSP) {
if o, ok := oidOf(f[0]); !ok || !bytes.Equal(o, oidRIOCSP) {
return formErr("crls holds only OCSP responses")
}
out.OCSP = append(out.OCSP, f[1])
@ -303,7 +354,9 @@ func parseSignerInfo(b []byte, sd *SignedData, token bool) (*SignerInfo, error)
return s, nil
}
// findSigner returns the one certificate that the sid names.
// findSigner returns the one certificate that the sid names, comparing the
// DER of the issuer and the content of the serial number, or the
// keyIdentifier.
func findSigner(sid []byte, certs []*Cert) (*Cert, error) {
var found *Cert
n := 0
@ -313,10 +366,7 @@ func findSigner(sid []byte, certs []*Cert) (*Cert, error) {
if err != nil || len(p) != 2 || p[0][0] != 0x30 || p[1][0] != 0x02 {
return nil, formErr("issuerAndSerialNumber")
}
var serial *big.Int
if _, err := asn1.Unmarshal(p[1], &serial); err != nil {
return nil, formErr("issuerAndSerialNumber")
}
serial, _ := der.Content(p[1])
for _, c := range certs {
if c.hasSID(p[0], serial) {
found, n = c, n+1
@ -336,20 +386,21 @@ func findSigner(sid []byte, certs []*Cert) (*Cert, error) {
return nil, formErr("a SignerIdentifier")
}
if n != 1 {
return nil, formErr("a sid that names %d certificates, not one", n)
return nil, formErr("a sid that names %d certificates of the profile, not one", n)
}
return found, nil
}
// attrSet holds the attributes of a SET OF Attribute: the values of each type
// and the number of attributes of each type, which is not the number of values.
// and the number of attributes of each type, which is not the number of
// values. Both are kept by the bytes of the object identifier.
type attrSet struct {
vals map[string][][]byte
count map[string]int
}
func (a attrSet) get(oid asn1.ObjectIdentifier) ([][]byte, int) {
return a.vals[oid.String()], a.count[oid.String()]
func (a attrSet) get(o []byte) ([][]byte, int) {
return a.vals[string(o)], a.count[string(o)]
}
// attrs reads the SET OF Attribute b. An attribute needs at least one value
@ -363,26 +414,26 @@ func attrs(b []byte) (attrSet, error) {
out := attrSet{vals: map[string][][]byte{}, count: map[string]int{}}
for _, a := range kids {
_, p, err := der.Split(a)
if err != nil || len(p) != 2 || a[0] != 0x30 || p[0][0] != 0x06 || p[1][0] != 0x31 {
if err != nil || len(p) != 2 || a[0] != 0x30 || p[1][0] != 0x31 {
return attrSet{}, formErr("an Attribute")
}
var oid asn1.ObjectIdentifier
if _, err := asn1.Unmarshal(p[0], &oid); err != nil {
o, ok := oidOf(p[0])
if !ok {
return attrSet{}, formErr("an Attribute")
}
_, vals, err := der.Split(p[1])
if err != nil || len(vals) == 0 || !der.SetOfSorted(vals) {
return attrSet{}, formErr("the values of an attribute are not a non-empty SET OF in DER order")
}
out.vals[oid.String()] = append(out.vals[oid.String()], vals...)
out.count[oid.String()]++
out.vals[string(o)] = append(out.vals[string(o)], vals...)
out.count[string(o)]++
}
return out, nil
}
// one returns the only value of the only attribute of the type.
func one(m attrSet, oid asn1.ObjectIdentifier, name string) ([]byte, error) {
v, n := m.get(oid)
func one(m attrSet, o []byte, name string) ([]byte, error) {
v, n := m.get(o)
if n != 1 || len(v) != 1 {
return nil, formErr("%s: %d attributes with %d values, not one with one", name, n, len(v))
}
@ -401,13 +452,12 @@ func parseSignedAttrs(s *SignerInfo, token bool) error {
if err != nil {
return err
}
want := oidData
want, name := oidData, "id-data"
if token {
want = oidTSTInfo
want, name = oidTSTInfo, "id-ct-TSTInfo"
}
var got asn1.ObjectIdentifier
if _, err := asn1.Unmarshal(ct, &got); err != nil || !got.Equal(want) {
return formErr("content-type is not %v", want)
if got, ok := oidOf(ct); !ok || !bytes.Equal(got, want) {
return formErr("content-type is not %s", name)
}
md, err := one(m, oidMessageDig, "message-digest")
if err != nil {

@ -6,9 +6,8 @@ import (
"crypto/ecdsa"
"crypto/elliptic"
"crypto/rsa"
"crypto/x509"
"encoding/asn1"
"errors"
"math/big"
"time"
"g.activething.com/go/DateKeys/internal/der"
@ -29,15 +28,19 @@ const (
)
var (
oidRSAEncryption = asn1.ObjectIdentifier{1, 2, 840, 113549, 1, 1, 1}
oidSHA256RSA = asn1.ObjectIdentifier{1, 2, 840, 113549, 1, 1, 11}
oidSHA384RSA = asn1.ObjectIdentifier{1, 2, 840, 113549, 1, 1, 12}
oidSHA512RSA = asn1.ObjectIdentifier{1, 2, 840, 113549, 1, 1, 13}
oidPSS = asn1.ObjectIdentifier{1, 2, 840, 113549, 1, 1, 10}
oidMGF1 = asn1.ObjectIdentifier{1, 2, 840, 113549, 1, 1, 8}
oidECDSA256 = asn1.ObjectIdentifier{1, 2, 840, 10045, 4, 3, 2}
oidECDSA384 = asn1.ObjectIdentifier{1, 2, 840, 10045, 4, 3, 3}
oidECDSA512 = asn1.ObjectIdentifier{1, 2, 840, 10045, 4, 3, 4}
oidRSAEncryption = oid("1.2.840.113549.1.1.1")
oidSHA256RSA = oid("1.2.840.113549.1.1.11")
oidSHA384RSA = oid("1.2.840.113549.1.1.12")
oidSHA512RSA = oid("1.2.840.113549.1.1.13")
oidPSS = oid("1.2.840.113549.1.1.10")
oidMGF1 = oid("1.2.840.113549.1.1.8")
oidECDSA256 = oid("1.2.840.10045.4.3.2")
oidECDSA384 = oid("1.2.840.10045.4.3.3")
oidECDSA512 = oid("1.2.840.10045.4.3.4")
oidECPublicKey = oid("1.2.840.10045.2.1")
oidP256 = oid("1.2.840.10045.3.1.7")
oidP384 = oid("1.3.132.0.34")
oidP521 = oid("1.3.132.0.35")
)
type scheme int
@ -65,24 +68,24 @@ func (s *SignerInfo) params() (crypto.Hash, scheme, bool) {
default:
h = crypto.SHA512
}
oid, params := s.SigAlg.OID, s.SigAlg.Params
o, params := s.SigAlg.OID, s.SigAlg.Params
nullOrAbsent := params == nil || bytes.Equal(params, []byte{5, 0})
switch {
case oid.Equal(oidRSAEncryption):
case bytes.Equal(o, oidRSAEncryption):
return h, schemePKCS1, nullOrAbsent
case oid.Equal(oidSHA256RSA):
case bytes.Equal(o, oidSHA256RSA):
return h, schemePKCS1, nullOrAbsent && h == crypto.SHA256
case oid.Equal(oidSHA384RSA):
case bytes.Equal(o, oidSHA384RSA):
return h, schemePKCS1, nullOrAbsent && h == crypto.SHA384
case oid.Equal(oidSHA512RSA):
case bytes.Equal(o, oidSHA512RSA):
return h, schemePKCS1, nullOrAbsent && h == crypto.SHA512
case oid.Equal(oidECDSA256):
case bytes.Equal(o, oidECDSA256):
return h, schemeECDSA, params == nil && h == crypto.SHA256
case oid.Equal(oidECDSA384):
case bytes.Equal(o, oidECDSA384):
return h, schemeECDSA, params == nil && h == crypto.SHA384
case oid.Equal(oidECDSA512):
case bytes.Equal(o, oidECDSA512):
return h, schemeECDSA, params == nil && h == crypto.SHA512
case oid.Equal(oidPSS):
case bytes.Equal(o, oidPSS):
return h, schemePSS, pssParamsOK(params, newHash().Size(), s.DigestAlg)
}
return 0, 0, false
@ -109,18 +112,17 @@ func pssParamsOK(params []byte, hashLen int, digest algID) bool {
switch e[0] {
case 0xa0:
a, err := parseAlgID(in[0])
hashOK = err == nil && a.OID.Equal(digest.OID) && (a.Params == nil || bytes.Equal(a.Params, []byte{5, 0}))
hashOK = err == nil && bytes.Equal(a.OID, digest.OID) && (a.Params == nil || bytes.Equal(a.Params, []byte{5, 0}))
case 0xa1:
a, err := parseAlgID(in[0])
if err != nil || !a.OID.Equal(oidMGF1) || a.Params == nil {
if err != nil || !bytes.Equal(a.OID, oidMGF1) || a.Params == nil {
return false
}
inner, err := parseAlgID(a.Params)
mgfOK = err == nil && inner.OID.Equal(digest.OID) && (inner.Params == nil || bytes.Equal(inner.Params, []byte{5, 0}))
mgfOK = err == nil && bytes.Equal(inner.OID, digest.OID) && (inner.Params == nil || bytes.Equal(inner.Params, []byte{5, 0}))
case 0xa2:
var n int
_, err := asn1.Unmarshal(in[0], &n)
saltOK = err == nil && n == hashLen
n, ok := smallInt(in[0])
saltOK = ok && n == hashLen
default: // [3] trailerField is 1, its DEFAULT: DER does not write it
return false
}
@ -130,73 +132,124 @@ func pssParamsOK(params []byte, hashLen int, digest algID) bool {
return hashOK && mgfOK && saltOK
}
// publicKey returns the key of the certificate when it is in the table:
// RSA of 2048 to 4096 bits with an odd exponent from 3 to 2^31 - 1, or ECDSA
// on P-256, P-384 or P-521.
// smallInt reads an INTEGER element of at most 4 bytes that is not negative.
func smallInt(b []byte) (int, bool) {
if len(b) == 0 || b[0] != 0x02 {
return 0, false
}
c, err := der.Content(b)
if err != nil || len(c) == 0 || len(c) > 4 || c[0]&0x80 != 0 {
return 0, false
}
n := 0
for _, x := range c {
n = n<<8 | int(x)
}
return n, true
}
// publicKey returns the key of the certificate when the table has it (spec
// §29.10): a SubjectPublicKeyInfo of rsaEncryption with NULL parameters and
// an RSAPublicKey of exactly a modulus and an exponent, the modulus odd and
// of 2048 to 4096 bits and the exponent odd from 3 to 2^31 - 1; or of
// id-ecPublicKey with the named curve P-256, P-384 or P-521 and the
// uncompressed form of a point of it. Anything else is not usable.
func (c *Cert) publicKey() (any, scheme, bool) {
k, err := x509.ParsePKIXPublicKey(c.SPKI)
_, f, err := der.Split(c.SPKI)
if err != nil || len(f) != 2 || f[0][0] != 0x30 || f[1][0] != 0x03 {
return nil, 0, false
}
alg, err := parseAlgID(f[0])
if err != nil {
return nil, 0, false
}
switch k := k.(type) {
case *rsa.PublicKey:
bits := k.N.BitLen()
if bits < 2048 || bits > 4096 || k.E < 3 || k.E%2 == 0 || int64(k.E) > 1<<31-1 {
bits, err := der.Content(f[1])
if err != nil || len(bits) < 2 || bits[0] != 0 {
return nil, 0, false
}
return k, schemePKCS1, true
case *ecdsa.PublicKey:
switch k.Curve {
case elliptic.P256(), elliptic.P384(), elliptic.P521():
return k, schemeECDSA, true
key := bits[1:]
switch {
case bytes.Equal(alg.OID, oidRSAEncryption) && bytes.Equal(alg.Params, []byte{5, 0}):
if der.Check(key) != nil {
return nil, 0, false
}
id, ne, err := der.Split(key)
if err != nil || id != 0x30 || len(ne) != 2 || ne[0][0] != 0x02 || ne[1][0] != 0x02 {
return nil, 0, false
}
nb, _ := der.Content(ne[0])
eb, _ := der.Content(ne[1])
if nb[0]&0x80 != 0 || eb[0]&0x80 != 0 || len(eb) > 4 {
return nil, 0, false
}
n := new(big.Int).SetBytes(nb)
e := new(big.Int).SetBytes(eb).Int64()
if b := n.BitLen(); b < 2048 || b > 4096 || n.Bit(0) == 0 || e < 3 || e%2 == 0 || e > 1<<31-1 {
return nil, 0, false
}
// algorithmsOK reports whether the algorithms of the SignerInfo and the key of
// its certificate are in the table of spec §29.10.
func (s *SignerInfo) algorithmsOK() bool {
_, sch, ok := s.params()
if !ok {
return false
}
_, ksch, ok := s.Cert.publicKey()
return &rsa.PublicKey{N: n, E: int(e)}, schemePKCS1, true
case bytes.Equal(alg.OID, oidECPublicKey):
curveOID, ok := oidOf(alg.Params)
if !ok {
return false
return nil, 0, false
}
var curve elliptic.Curve
switch {
case bytes.Equal(curveOID, oidP256):
curve = elliptic.P256()
case bytes.Equal(curveOID, oidP384):
curve = elliptic.P384()
case bytes.Equal(curveOID, oidP521):
curve = elliptic.P521()
default:
return nil, 0, false
}
k, err := ecdsa.ParseUncompressedPublicKey(curve, key)
if err != nil {
return nil, 0, false
}
return sch == ksch || sch == schemePSS && ksch == schemePKCS1
return k, schemeECDSA, true
}
return nil, 0, false
}
// Check checks the signature of the SignerInfo over message, the bytes that
// the signature is detached from (spec §29.10): not verifiable for an
// algorithm outside the table; invalid when the message-digest is not the
// hash of message or the signature of the signedAttrs does not verify.
// the signature is detached from (spec §29.10), in the order of the spec: not
// verifiable for an algorithm, a key or a curve outside the table; invalid
// when the message-digest is not the hash of message, or the signature of the
// signedAttrs does not verify with the key of the certificate, which is the
// case of a key of a scheme other than the one of the algorithm.
func (s *SignerInfo) Check(message []byte) Result {
if !s.algorithmsOK() {
h, sch, ok := s.params()
if !ok {
return NotVerifiable
}
key, ksch, ok := s.Cert.publicKey()
if !ok {
return NotVerifiable
}
h, sch, _ := s.params()
if sum := hashBytes(h, message); !bytes.Equal(sum, s.MessageDigest) {
return Invalid
}
if sch != ksch && !(sch == schemePSS && ksch == schemePKCS1) {
return Invalid
}
// The signature covers the signedAttrs with the tag of a SET.
attrs := bytes.Clone(s.SignedAttrs)
attrs[0] = 0x31
digest := hashBytes(h, attrs)
key, _, _ := s.Cert.publicKey()
var ok bool
var valid bool
switch k := key.(type) {
case *rsa.PublicKey:
if sch == schemePSS {
ok = rsa.VerifyPSS(k, h, digest, s.Signature, &rsa.PSSOptions{SaltLength: h.Size(), Hash: h}) == nil
valid = rsa.VerifyPSS(k, h, digest, s.Signature, &rsa.PSSOptions{SaltLength: h.Size(), Hash: h}) == nil
} else {
ok = rsa.VerifyPKCS1v15(k, h, digest, s.Signature) == nil
valid = rsa.VerifyPKCS1v15(k, h, digest, s.Signature) == nil
}
case *ecdsa.PublicKey:
ok = ecdsa.VerifyASN1(k, digest, s.Signature)
valid = ecdsa.VerifyASN1(k, digest, s.Signature)
}
if !ok {
if !valid {
return Invalid
}
return Valid
@ -216,7 +269,7 @@ type Token struct {
GenTime time.Time
Accuracy time.Duration
// ImprintAlg is the hash of the messageImprint, and Imprint the hash.
ImprintAlg asn1.ObjectIdentifier
ImprintAlg algID
Imprint []byte
// TSA is the certificate of the time-stamping authority.
TSA *Cert
@ -224,9 +277,9 @@ type Token struct {
data *SignedData
}
// maxAccuracy bounds the seconds of accuracy: far above any real one, and far
// below what would overflow a Duration.
const maxAccuracy = 1 << 31
// maxAccuracy bounds the seconds of accuracy (spec §29.11): far above any
// real one, and far below what would overflow a Duration.
const maxAccuracy = 1<<31 - 1
// ParseToken reads a time-stamp token. It fails with ErrForm when the form
// breaks the profile, and with ErrAlgorithm when an algorithm is outside the
@ -237,23 +290,23 @@ func ParseToken(b []byte) (*Token, error) {
return nil, err
}
// The TSTInfo is an OCTET STRING inside the token, so the check of the
// token did not reach it, and encoding/asn1 would let through what DER
// forbids: it is read here, field by field.
// token did not reach it: it is read here, field by field.
t, imprintAlg, hash, err := parseTSTInfo(sd.EContent)
if err != nil {
return nil, err
}
t.TSA, t.data = sd.Signers[0].Cert, sd
ia, err := parseAlgID(imprintAlg)
if err != nil {
if t.ImprintAlg, err = parseAlgID(imprintAlg); err != nil {
return nil, err
}
t.ImprintAlg, t.Imprint = ia.OID, hash
newHash, ok := ia.hashOf()
if ok && len(hash) != newHash().Size() {
return nil, formErr("a messageImprint of the wrong length")
t.Imprint = hash
if _, ok := t.ImprintAlg.hashOf(); !ok {
return nil, ErrAlgorithm
}
if _, _, ok := sd.Signers[0].params(); !ok {
return nil, ErrAlgorithm
}
if !ok || !sd.Signers[0].algorithmsOK() {
if _, _, ok := t.TSA.publicKey(); !ok {
return nil, ErrAlgorithm
}
return t, nil
@ -273,11 +326,7 @@ func parseTSTInfo(b []byte) (*Token, []byte, []byte, error) {
if err != nil || id != 0x30 || len(f) < 5 {
return bad("not a SEQUENCE of at least five fields")
}
var version int
if f[0][0] != 0x02 {
return bad("the version")
}
if _, err := asn1.Unmarshal(f[0], &version); err != nil || version != 1 {
if v, ok := smallInt(f[0]); !ok || v != 1 {
return bad("the version is not 1")
}
if f[1][0] != 0x06 || f[3][0] != 0x02 || f[4][0] != 0x18 {
@ -291,9 +340,9 @@ func parseTSTInfo(b []byte) (*Token, []byte, []byte, error) {
if err != nil {
return bad("the messageImprint")
}
gen, err := parseGenTime(f[4])
gen, _, err := der.ParseTime(f[4])
if err != nil {
return bad(err.Error())
return bad("genTime: " + err.Error())
}
t := &Token{GenTime: gen}
rest := f[5:]
@ -324,47 +373,10 @@ func parseTSTInfo(b []byte) (*Token, []byte, []byte, error) {
return t, mi[0], hash, nil
}
// parseGenTime reads a GeneralizedTime as RFC 3161 and DER write it:
// YYYYMMDDHHMMSS, a fraction without a trailing zero, and Z.
func parseGenTime(b []byte) (time.Time, error) {
c, err := der.Content(b)
if err != nil {
return time.Time{}, errors.New("genTime")
}
s := string(c)
if len(s) < 15 || s[len(s)-1] != 'Z' {
return time.Time{}, errors.New("genTime is not in UTC with the letter Z")
}
body := s[:len(s)-1]
t, err := time.Parse("20060102150405", body[:14])
if err != nil {
return time.Time{}, errors.New("genTime does not parse")
}
if frac := body[14:]; frac != "" {
if len(frac) < 2 || frac[0] != '.' || frac[len(frac)-1] == '0' {
return time.Time{}, errors.New("genTime has a fraction that DER does not write")
}
var nanos int
digits := frac[1:]
for i := 0; i < len(digits); i++ {
if digits[i] < '0' || digits[i] > '9' {
return time.Time{}, errors.New("genTime has a fraction that is not digits")
}
}
for i := 0; i < 9; i++ {
nanos *= 10
if i < len(digits) {
nanos += int(digits[i] - '0')
}
}
t = t.Add(time.Duration(nanos))
}
return t, nil
}
// parseAccuracy reads Accuracy: seconds from 0, and millis and micros from 1
// to 999, in that order, each optional (RFC 3161 2.4.2). A negative number
// would make a seal after the opening date look before it.
// parseAccuracy reads Accuracy: seconds from 0 to 2^31 - 1, and millis and
// micros from 1 to 999, in that order, each optional (RFC 3161 2.4.2, spec
// §29.11), each a minimal INTEGER. A negative number would make a seal after
// the opening date look before it.
func parseAccuracy(b []byte) (time.Duration, error) {
_, f, err := der.Split(b)
if err != nil {
@ -372,9 +384,9 @@ func parseAccuracy(b []byte) (time.Duration, error) {
}
var total time.Duration
if len(f) > 0 && f[0][0] == 0x02 {
var secs int64
if _, err := asn1.Unmarshal(f[0], &secs); err != nil || secs < 0 || secs > maxAccuracy {
return 0, errors.New("accuracy seconds outside 0 to 2^31")
secs, ok := smallInt(f[0])
if !ok || secs > maxAccuracy {
return 0, errors.New("accuracy seconds outside 0 to 2^31 - 1")
}
total += time.Duration(secs) * time.Second
f = f[1:]
@ -385,8 +397,8 @@ func parseAccuracy(b []byte) (time.Duration, error) {
}{{0x80, time.Millisecond}, {0x81, time.Microsecond}} {
if len(f) > 0 && f[0][0] == part.tag {
c, err := der.Content(f[0])
if err != nil || len(c) < 1 || len(c) > 2 || c[0]&0x80 != 0 {
return 0, errors.New("accuracy millis or micros")
if err != nil || len(c) < 1 || len(c) > 2 || c[0]&0x80 != 0 || len(c) == 2 && c[0] == 0 && c[1]&0x80 == 0 {
return 0, errors.New("accuracy millis or micros that are not a minimal INTEGER")
}
n := 0
for _, x := range c {
@ -407,18 +419,19 @@ func parseAccuracy(b []byte) (time.Duration, error) {
// ImprintIsSHA256 reports whether the messageImprint uses SHA-256, which a
// seal of seal_type 2 requires (spec §29.11).
func (t *Token) ImprintIsSHA256() bool { return t.ImprintAlg.Equal(oidSHA256) }
func (t *Token) ImprintIsSHA256() bool { return bytes.Equal(t.ImprintAlg.OID, oidSHA256) }
// Check verifies the token over subject, the bytes that it seals: the
// message-digest is the hash of the TSTInfo, the signature of the TSA
// verifies, the messageImprint is the hash of subject and the certificate of
// the TSA is valid at genTime. It returns false for the verdict S3.
// verifies, the messageImprint is the hash of subject, of any length, and the
// certificate of the TSA is valid at genTime. It returns false for the
// verdict S3.
func (t *Token) Check(subject []byte) bool {
s := t.data.Signers[0]
if s.Check(t.data.EContent) != Valid {
return false
}
newHash, _ := algID{OID: t.ImprintAlg}.hashOf()
newHash, _ := t.ImprintAlg.hashOf()
h := newHash()
h.Write(subject)
return bytes.Equal(h.Sum(nil), t.Imprint) && t.TSA.ValidAt(t.GenTime)

@ -2,9 +2,10 @@
// Rules of X.690, as spec v0.11 §29.10 asks of a CMS signature before it
// looks inside it: definite and minimal lengths, no high tag numbers, no
// constructed form of a type that DER only has primitive, canonical BOOLEAN,
// INTEGER, NULL, OBJECT IDENTIFIER and BIT STRING, and no bytes after the
// element. Go's encoding/asn1 accepts some of what DER forbids, and a
// signature that two implementations read the same must not depend on it.
// INTEGER, NULL, OBJECT IDENTIFIER, BIT STRING, UTCTime and GeneralizedTime,
// and no bytes after the element. Go's encoding/asn1 accepts some of what DER
// forbids, and a signature that two implementations read the same must not
// depend on it.
//
// The order of the elements of a SET OF cannot be checked without a schema:
// SetOfSorted does it for the callers that know theirs.
@ -14,6 +15,8 @@ import (
"bytes"
"errors"
"fmt"
"strings"
"time"
)
const maxDepth = 32
@ -63,17 +66,98 @@ func Content(b []byte) ([]byte, error) {
}
// SetOfSorted reports whether the encodings are in ascending order of their
// bytes, as DER requires of the elements of a SET OF (X.690 11.6), and
// without repetitions: a SET OF of this profile has none.
// bytes, as DER requires of the elements of a SET OF (X.690 11.6). Equal
// elements may repeat, side by side: X.690 does not forbid it, and a time-
// stamping authority may send its certificate twice. Whoever counts the
// elements of a SET OF decides what a repetition means.
func SetOfSorted(elems [][]byte) bool {
for i := 1; i < len(elems); i++ {
if bytes.Compare(elems[i-1], elems[i]) >= 0 {
if bytes.Compare(elems[i-1], elems[i]) > 0 {
return false
}
}
return true
}
// ParseTime reads a UTCTime or a GeneralizedTime element as DER writes them
// (X.690 11.7 and 11.8): YYMMDDHHMMSSZ, with the years 50 to 99 in the 20th
// century (RFC 5280 4.1.2.5.1), or YYYYMMDDHHMMSS, an optional fraction of
// seconds without a trailing zero, and Z. A date or a time that does not
// exist, a second 60 included, is refused. fraction reports whether a
// GeneralizedTime has one.
func ParseTime(b []byte) (t time.Time, fraction bool, err error) {
if len(b) < 2 || (b[0] != 0x17 && b[0] != 0x18) {
return time.Time{}, false, errors.New("der: not a UTCTime or a GeneralizedTime")
}
c, err := Content(b)
if err != nil {
return time.Time{}, false, err
}
return parseTime(b[0], string(c))
}
func parseTime(tag byte, s string) (time.Time, bool, error) {
bad := errors.New("der: a time that is not in the form of DER")
if len(s) < 13 || s[len(s)-1] != 'Z' {
return time.Time{}, false, bad
}
body, frac := s[:len(s)-1], ""
var year int
switch tag {
case 0x17:
if len(body) != 12 || !digits(body) {
return time.Time{}, false, bad
}
year = atoi(body[:2]) + 1900
if year < 1950 {
year += 100
}
body = body[2:]
default:
if dot := strings.IndexByte(body, '.'); dot >= 0 {
body, frac = body[:dot], body[dot+1:]
if frac == "" || frac[len(frac)-1] == '0' || !digits(frac) {
return time.Time{}, false, bad
}
}
if len(body) != 14 || !digits(body) {
return time.Time{}, false, bad
}
year = atoi(body[:4])
body = body[4:]
}
month, day, hour, minute, second := atoi(body[0:2]), atoi(body[2:4]), atoi(body[4:6]), atoi(body[6:8]), atoi(body[8:10])
if month < 1 || month > 12 || day < 1 || hour > 23 || minute > 59 || second > 59 ||
day > time.Date(year, time.Month(month)+1, 0, 0, 0, 0, 0, time.UTC).Day() {
return time.Time{}, false, errors.New("der: a date or a time that does not exist")
}
nanos := 0
for i := 0; i < 9; i++ {
nanos *= 10
if i < len(frac) {
nanos += int(frac[i] - '0')
}
}
return time.Date(year, time.Month(month), day, hour, minute, second, nanos, time.UTC), frac != "", nil
}
func digits(s string) bool {
for i := 0; i < len(s); i++ {
if s[i] < '0' || s[i] > '9' {
return false
}
}
return s != ""
}
func atoi(s string) int {
n := 0
for i := 0; i < len(s); i++ {
n = n*10 + int(s[i]-'0')
}
return n
}
// header returns the length of the identifier and length octets of the
// element at the start of b, and the length of its content, which must fit
// in b.
@ -183,7 +267,11 @@ func checkPrimitive(tag byte, c []byte) error {
}
start = x&0x80 == 0
}
case 4, 12, 19, 20, 22, 23, 24, 26, 28, 30: // OCTET STRING and the string and time types of X.509
case 23, 24: // UTCTime, GeneralizedTime
if _, _, err := parseTime(tag, string(c)); err != nil {
return err
}
case 4, 12, 19, 20, 22, 26, 28, 30: // OCTET STRING and the string types of X.509
case 16, 17:
return fmt.Errorf("der: the universal type %d in primitive form", tag)
default:

@ -3,6 +3,7 @@ package der
import (
"encoding/hex"
"testing"
"time"
)
func TestCheck(t *testing.T) {
@ -14,6 +15,7 @@ func TestCheck(t *testing.T) {
{"a long length", "04" + "8180" + zeros(128), true},
{"a long form under 128", "0481" + "01" + "00", false},
{"a length with a leading zero", "04820001" + "00", false},
{"a length of 128 with a leading zero", "04820080" + zeros(128), false},
{"an indefinite length", "30800000", false},
{"a high tag number", "1f0100", false},
{"truncated", "0402aa", false},
@ -38,6 +40,19 @@ func TestCheck(t *testing.T) {
{"a reserved universal tag", "0e0141", false},
{"a SEQUENCE of the end of contents", "30020000", false},
{"UTF8String", "0c026162", true},
// Times in the forms of DER (X.690 11.7, 11.8).
{"UTCTime", "170d" + hex.EncodeToString([]byte("250101120000Z")), true},
{"UTCTime without seconds", "170b" + hex.EncodeToString([]byte("2501011200Z")), false},
{"UTCTime with an offset", "1711" + hex.EncodeToString([]byte("250101120000+0100")), false},
{"UTCTime of 30 February", "170d" + hex.EncodeToString([]byte("250230120000Z")), false},
{"UTCTime with second 60", "170d" + hex.EncodeToString([]byte("250101235960Z")), false},
{"a UTCTime that is not a time", "170a" + hex.EncodeToString([]byte("not a time")), false},
{"GeneralizedTime", "180f" + hex.EncodeToString([]byte("20250101120000Z")), true},
{"GeneralizedTime with a fraction", "1812" + hex.EncodeToString([]byte("20250101120000.25Z")), true},
{"GeneralizedTime with a trailing zero", "1813" + hex.EncodeToString([]byte("20250101120000.250Z")), false},
{"GeneralizedTime with an empty fraction", "1810" + hex.EncodeToString([]byte("20250101120000.Z")), false},
{"GeneralizedTime without Z", "180e" + hex.EncodeToString([]byte("20250101120000")), false},
{"GeneralizedTime with a comma", "1812" + hex.EncodeToString([]byte("20250101120000,25Z")), false},
} {
b, err := hex.DecodeString(tc.hex)
if err != nil {
@ -57,13 +72,54 @@ func zeros(n int) string {
return string(b)
}
// The elements of a SET OF go in ascending order, and equal ones may repeat
// (X.690 11.6).
func TestSetOfSorted(t *testing.T) {
a, b := []byte{0x02, 0x01, 0x01}, []byte{0x02, 0x01, 0x02}
if !SetOfSorted([][]byte{a, b}) || SetOfSorted([][]byte{b, a}) || SetOfSorted([][]byte{a, a}) {
if !SetOfSorted([][]byte{a, b}) || SetOfSorted([][]byte{b, a}) || !SetOfSorted([][]byte{a, a, b}) || SetOfSorted([][]byte{a, b, a}) {
t.Error("SetOfSorted")
}
}
// Elements nested 32 levels below the outer one are DER; one more is too deep.
func TestDepth(t *testing.T) {
nested := func(n int) []byte {
b := []byte{0x05, 0x00}
for range n {
b = append([]byte{0x30, byte(len(b))}, b...)
}
return b
}
if err := Check(nested(maxDepth)); err != nil {
t.Errorf("%d levels: %v", maxDepth, err)
}
if err := Check(nested(maxDepth + 1)); err == nil {
t.Errorf("%d levels: accepted", maxDepth+1)
}
}
func TestParseTime(t *testing.T) {
for _, c := range []struct {
el string
want time.Time
frac bool
}{
{"\x17\x0d" + "491231235959Z", time.Date(2049, 12, 31, 23, 59, 59, 0, time.UTC), false},
{"\x17\x0d" + "500101000000Z", time.Date(1950, 1, 1, 0, 0, 0, 0, time.UTC), false},
{"\x18\x13" + "20240229120000.125Z", time.Date(2024, 2, 29, 12, 0, 0, 125e6, time.UTC), true},
} {
got, frac, err := ParseTime([]byte(c.el))
if err != nil || !got.Equal(c.want) || frac != c.frac {
t.Errorf("%q: %v %v %v", c.el, got, frac, err)
}
}
for _, bad := range []string{"\x18\x0f" + "20230229120000Z", "\x04\x0d" + "491231235959Z", "\x17"} {
if _, _, err := ParseTime([]byte(bad)); err == nil {
t.Errorf("%q: accepted", bad)
}
}
}
func TestSplit(t *testing.T) {
b, _ := hex.DecodeString("30050201010500")
if err := Check(b); err != nil {

Loading…
Cancel
Save

Powered by TurnKey Linux.