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.
455 lines
14 KiB
455 lines
14 KiB
package cms
|
|
|
|
import (
|
|
"bytes"
|
|
"crypto"
|
|
"crypto/ecdsa"
|
|
"crypto/elliptic"
|
|
"crypto/rsa"
|
|
"errors"
|
|
"math/big"
|
|
"time"
|
|
|
|
"g.activething.com/go/DateKeys/internal/der"
|
|
)
|
|
|
|
// Result is the result of checking the signature of a SignerInfo (spec
|
|
// §29.10, "Verificación").
|
|
type Result int
|
|
|
|
const (
|
|
// Valid: the message-digest is the hash of the message and the signature
|
|
// of the signedAttrs verifies with the key of the certificate.
|
|
Valid Result = iota
|
|
// Invalid: one of the two does not hold.
|
|
Invalid
|
|
// NotVerifiable: an algorithm, a key size or a curve outside the table.
|
|
NotVerifiable
|
|
)
|
|
|
|
var (
|
|
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
|
|
|
|
const (
|
|
schemePKCS1 scheme = iota + 1
|
|
schemePSS
|
|
schemeECDSA
|
|
)
|
|
|
|
// params returns the hash, the signature scheme and the hash that the
|
|
// signature algorithm itself names, when it does, of the SignerInfo, and
|
|
// whether they are in the table.
|
|
func (s *SignerInfo) params() (crypto.Hash, scheme, bool) {
|
|
newHash, ok := s.DigestAlg.hashOf()
|
|
if !ok {
|
|
return 0, 0, false
|
|
}
|
|
var h crypto.Hash
|
|
switch newHash().Size() {
|
|
case 32:
|
|
h = crypto.SHA256
|
|
case 48:
|
|
h = crypto.SHA384
|
|
default:
|
|
h = crypto.SHA512
|
|
}
|
|
o, params := s.SigAlg.OID, s.SigAlg.Params
|
|
nullOrAbsent := params == nil || bytes.Equal(params, []byte{5, 0})
|
|
switch {
|
|
case bytes.Equal(o, oidRSAEncryption):
|
|
return h, schemePKCS1, nullOrAbsent
|
|
case bytes.Equal(o, oidSHA256RSA):
|
|
return h, schemePKCS1, nullOrAbsent && h == crypto.SHA256
|
|
case bytes.Equal(o, oidSHA384RSA):
|
|
return h, schemePKCS1, nullOrAbsent && h == crypto.SHA384
|
|
case bytes.Equal(o, oidSHA512RSA):
|
|
return h, schemePKCS1, nullOrAbsent && h == crypto.SHA512
|
|
case bytes.Equal(o, oidECDSA256):
|
|
return h, schemeECDSA, params == nil && h == crypto.SHA256
|
|
case bytes.Equal(o, oidECDSA384):
|
|
return h, schemeECDSA, params == nil && h == crypto.SHA384
|
|
case bytes.Equal(o, oidECDSA512):
|
|
return h, schemeECDSA, params == nil && h == crypto.SHA512
|
|
case bytes.Equal(o, oidPSS):
|
|
return h, schemePSS, pssParamsOK(params, newHash().Size(), s.DigestAlg)
|
|
}
|
|
return 0, 0, false
|
|
}
|
|
|
|
// pssParamsOK checks RSASSA-PSS-params (RFC 4055): the hash of digestAlgorithm,
|
|
// MGF1 with that hash, a salt of its length and trailerField 1.
|
|
func pssParamsOK(params []byte, hashLen int, digest algID) bool {
|
|
if params == nil {
|
|
return false
|
|
}
|
|
id, f, err := der.Split(params)
|
|
if err != nil || id != 0x30 {
|
|
return false
|
|
}
|
|
var hashOK, mgfOK, saltOK bool
|
|
var last byte
|
|
for _, e := range f {
|
|
_, in, err := der.Split(e)
|
|
if err != nil || len(in) != 1 || e[0] <= last {
|
|
return false // the fields come in order of tag, each once
|
|
}
|
|
last = e[0]
|
|
switch e[0] {
|
|
case 0xa0:
|
|
a, err := parseAlgID(in[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 || !bytes.Equal(a.OID, oidMGF1) || a.Params == nil {
|
|
return false
|
|
}
|
|
inner, err := parseAlgID(a.Params)
|
|
mgfOK = err == nil && bytes.Equal(inner.OID, digest.OID) && (inner.Params == nil || bytes.Equal(inner.Params, []byte{5, 0}))
|
|
case 0xa2:
|
|
n, ok := smallInt(in[0])
|
|
saltOK = ok && n == hashLen
|
|
default: // [3] trailerField is 1, its DEFAULT: DER does not write it
|
|
return false
|
|
}
|
|
}
|
|
// hashAlgorithm and maskGenAlgorithm default to SHA-1, and the salt to 20
|
|
// bytes: none of them is in the table, so each must be present.
|
|
return hashOK && mgfOK && saltOK
|
|
}
|
|
|
|
// 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) {
|
|
_, 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
|
|
}
|
|
bits, err := der.Content(f[1])
|
|
if err != nil || len(bits) < 2 || bits[0] != 0 {
|
|
return nil, 0, false
|
|
}
|
|
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
|
|
}
|
|
return &rsa.PublicKey{N: n, E: int(e)}, schemePKCS1, true
|
|
case bytes.Equal(alg.OID, oidECPublicKey):
|
|
curveOID, ok := oidOf(alg.Params)
|
|
if !ok {
|
|
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 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), 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 {
|
|
h, sch, ok := s.params()
|
|
if !ok {
|
|
return NotVerifiable
|
|
}
|
|
key, ksch, ok := s.Cert.publicKey()
|
|
if !ok {
|
|
return NotVerifiable
|
|
}
|
|
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)
|
|
var valid bool
|
|
switch k := key.(type) {
|
|
case *rsa.PublicKey:
|
|
if sch == schemePSS {
|
|
valid = rsa.VerifyPSS(k, h, digest, s.Signature, &rsa.PSSOptions{SaltLength: h.Size(), Hash: h}) == nil
|
|
} else {
|
|
valid = rsa.VerifyPKCS1v15(k, h, digest, s.Signature) == nil
|
|
}
|
|
case *ecdsa.PublicKey:
|
|
valid = ecdsa.VerifyASN1(k, digest, s.Signature)
|
|
}
|
|
if !valid {
|
|
return Invalid
|
|
}
|
|
return Valid
|
|
}
|
|
|
|
func hashBytes(h crypto.Hash, b []byte) []byte {
|
|
x := h.New()
|
|
x.Write(b)
|
|
return x.Sum(nil)
|
|
}
|
|
|
|
// Token is a time-stamp token of RFC 3161 read with the profile of spec
|
|
// §29.11.
|
|
type Token struct {
|
|
// GenTime is t, and Accuracy the precision of the token, zero in the
|
|
// fields it does not carry. HasAccuracy reports whether it carries the
|
|
// field at all: without it, the token does not say its precision (spec
|
|
// v0.16, §29.11).
|
|
GenTime time.Time
|
|
Accuracy time.Duration
|
|
HasAccuracy bool
|
|
// Policy is the content of the object identifier of its policy.
|
|
Policy []byte
|
|
// ImprintAlg is the hash of the messageImprint, and Imprint the hash.
|
|
ImprintAlg algID
|
|
Imprint []byte
|
|
// TSA is the certificate of the time-stamping authority.
|
|
TSA *Cert
|
|
|
|
data *SignedData
|
|
}
|
|
|
|
// 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
|
|
// table, in that order (spec §29.11): the verdicts S2 and S1.
|
|
func ParseToken(b []byte) (*Token, error) {
|
|
sd, err := parse(b, true)
|
|
if err != nil {
|
|
return nil, err
|
|
}
|
|
// The TSTInfo is an OCTET STRING inside the token, so the check of the
|
|
// 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
|
|
if t.ImprintAlg, err = parseAlgID(imprintAlg); err != nil {
|
|
return nil, err
|
|
}
|
|
t.Imprint = hash
|
|
if _, ok := t.ImprintAlg.hashOf(); !ok {
|
|
return nil, ErrAlgorithm
|
|
}
|
|
if _, _, ok := sd.Signers[0].params(); !ok {
|
|
return nil, ErrAlgorithm
|
|
}
|
|
if _, _, ok := t.TSA.publicKey(); !ok {
|
|
return nil, ErrAlgorithm
|
|
}
|
|
return t, nil
|
|
}
|
|
|
|
// parseTSTInfo reads the TSTInfo of RFC 3161 3.2.1 in DER: the fields in
|
|
// order, each once, and nothing after the last. It returns the messageImprint
|
|
// algorithm, as the DER of its AlgorithmIdentifier, and the hash.
|
|
func parseTSTInfo(b []byte) (*Token, []byte, []byte, error) {
|
|
bad := func(what string) (*Token, []byte, []byte, error) {
|
|
return nil, nil, nil, formErr("the TSTInfo: %s", what)
|
|
}
|
|
if err := der.Check(b); err != nil {
|
|
return bad(err.Error())
|
|
}
|
|
id, f, err := der.Split(b)
|
|
if err != nil || id != 0x30 || len(f) < 5 {
|
|
return bad("not a SEQUENCE of at least five fields")
|
|
}
|
|
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 {
|
|
return bad("policy, serialNumber or genTime")
|
|
}
|
|
_, mi, err := der.Split(f[2])
|
|
if f[2][0] != 0x30 || err != nil || len(mi) != 2 || mi[0][0] != 0x30 || mi[1][0] != 0x04 {
|
|
return bad("the messageImprint")
|
|
}
|
|
hash, err := der.Content(mi[1])
|
|
if err != nil {
|
|
return bad("the messageImprint")
|
|
}
|
|
gen, _, err := der.ParseTime(f[4])
|
|
if err != nil {
|
|
return bad("genTime: " + err.Error())
|
|
}
|
|
policy, err := der.Content(f[1])
|
|
if err != nil {
|
|
return bad("policy")
|
|
}
|
|
t := &Token{GenTime: gen, Policy: policy}
|
|
rest := f[5:]
|
|
if len(rest) > 0 && rest[0][0] == 0x30 {
|
|
if t.Accuracy, err = parseAccuracy(rest[0]); err != nil {
|
|
return bad(err.Error())
|
|
}
|
|
t.HasAccuracy = true
|
|
rest = rest[1:]
|
|
}
|
|
if len(rest) > 0 && rest[0][0] == 0x01 {
|
|
if c, _ := der.Content(rest[0]); len(c) != 1 || c[0] != 0xff {
|
|
return bad("ordering FALSE is its default and DER does not write it")
|
|
}
|
|
rest = rest[1:]
|
|
}
|
|
if len(rest) > 0 && rest[0][0] == 0x02 { // nonce
|
|
rest = rest[1:]
|
|
}
|
|
if len(rest) > 0 && rest[0][0] == 0xa0 { // tsa
|
|
rest = rest[1:]
|
|
}
|
|
if len(rest) > 0 && rest[0][0] == 0xa1 { // extensions
|
|
rest = rest[1:]
|
|
}
|
|
if len(rest) != 0 {
|
|
return bad("a field out of its place, or one that does not exist")
|
|
}
|
|
return t, mi[0], hash, nil
|
|
}
|
|
|
|
// 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 {
|
|
return 0, errors.New("accuracy")
|
|
}
|
|
var total time.Duration
|
|
if len(f) > 0 && f[0][0] == 0x02 {
|
|
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:]
|
|
}
|
|
for _, part := range []struct {
|
|
tag byte
|
|
unit time.Duration
|
|
}{{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 || 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 {
|
|
n = n<<8 | int(x)
|
|
}
|
|
if n < 1 || n > 999 {
|
|
return 0, errors.New("accuracy millis or micros outside 1 to 999")
|
|
}
|
|
total += time.Duration(n) * part.unit
|
|
f = f[1:]
|
|
}
|
|
}
|
|
if len(f) != 0 {
|
|
return 0, errors.New("accuracy has a field out of its place")
|
|
}
|
|
return total, nil
|
|
}
|
|
|
|
// 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 bytes.Equal(t.ImprintAlg.OID, oidSHA256) }
|
|
|
|
// BTSP reports whether the policy of the token is the best practices
|
|
// time-stamp policy of ETSI EN 319 421 (0.4.0.2023.1.1), compared by the
|
|
// bytes of its DER, which requires accuracy in every token (spec v0.16,
|
|
// §29.11).
|
|
func (t *Token) BTSP() bool { return bytes.Equal(t.Policy, oidBTSP) }
|
|
|
|
// 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, 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, _ := t.ImprintAlg.hashOf()
|
|
h := newHash()
|
|
h.Write(subject)
|
|
return bytes.Equal(h.Sum(nil), t.Imprint) && t.TSA.ValidAt(t.GenTime)
|
|
}
|