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.
267 lines
21 KiB
267 lines
21 KiB
|
6 days ago
|
package cms_test
|
||
|
|
|
||
|
|
import (
|
||
|
|
"bytes"
|
||
|
|
"crypto"
|
||
|
|
"crypto/ecdsa"
|
||
|
|
"crypto/elliptic"
|
||
|
|
"encoding/asn1"
|
||
|
|
"math/big"
|
||
|
|
"testing"
|
||
|
|
"time"
|
||
|
|
|
||
|
|
"g.activething.com/go/DateKeys/internal/cms"
|
||
|
|
"g.activething.com/go/DateKeys/internal/cms/cmstest"
|
||
|
|
)
|
||
|
|
|
||
|
|
var (
|
||
|
|
p384Key = cmstest.ECKey(elliptic.P384())
|
||
|
|
p521Key = cmstest.ECKey(elliptic.P521())
|
||
|
|
)
|
||
|
|
|
||
|
|
// pss is the AlgorithmIdentifier of RSASSA-PSS with the fields of its
|
||
|
|
// parameters given.
|
||
|
|
func pss(fields ...[]byte) []byte { return cmstest.AlgID(cmstest.OIDPSS, cmstest.Seq(fields...)) }
|
||
|
|
|
||
|
|
// Spec §29.10, "Algoritmos" and step 2 of "Verificación": the closed table of
|
||
|
|
// algorithms, and a key of another scheme than its algorithm, which is
|
||
|
|
// invalid and not outside the table (step 3).
|
||
|
|
func TestAlgorithmTable(t *testing.T) {
|
||
|
|
alg, null := cmstest.AlgID, cmstest.Null
|
||
|
|
h0 := cmstest.TLV(0xa0, cmstest.HashAlg(crypto.SHA256))
|
||
|
|
m1 := cmstest.TLV(0xa1, alg(cmstest.OIDMGF1, cmstest.HashAlg(crypto.SHA256)))
|
||
|
|
s2 := cmstest.TLV(0xa2, cmstest.Int(32))
|
||
|
|
p384 := cmstest.NewCert(cmstest.CertSpec{CN: "P-384"}, p384Key)
|
||
|
|
p521 := cmstest.NewCert(cmstest.CertSpec{CN: "P-521"}, p521Key)
|
||
|
|
for name, tc := range map[string]struct {
|
||
|
|
s cmstest.Signer
|
||
|
|
o cmstest.Options
|
||
|
|
want cms.Result
|
||
|
|
}{
|
||
|
|
"SHA-1, ECDSA": {ana, cmstest.Options{Hash: crypto.SHA1}, cms.NotVerifiable},
|
||
|
|
"SHA-1, RSA": {luis, cmstest.Options{Hash: crypto.SHA1}, cms.NotVerifiable},
|
||
|
|
"SHA-1, and another message": {ana, cmstest.Options{Hash: crypto.SHA1, Message: []byte("other")}, cms.NotVerifiable},
|
||
|
|
"SHA-256 with NULL": {ana, cmstest.Options{DigestAlg: alg(cmstest.OIDSHA256, null())}, cms.Valid},
|
||
|
|
"SHA-256 with an INTEGER": {ana, cmstest.Options{DigestAlg: alg(cmstest.OIDSHA256, cmstest.Int(0))}, cms.NotVerifiable},
|
||
|
|
"P-256 with SHA-384": {ana, cmstest.Options{Hash: crypto.SHA384}, cms.Valid},
|
||
|
|
"P-256 with SHA-512": {ana, cmstest.Options{Hash: crypto.SHA512}, cms.Valid},
|
||
|
|
"P-384 with SHA-384": {p384, cmstest.Options{Hash: crypto.SHA384}, cms.Valid},
|
||
|
|
"P-521 with SHA-512": {p521, cmstest.Options{Hash: crypto.SHA512}, cms.Valid},
|
||
|
|
"P-521 with SHA-256": {p521, cmstest.Options{}, cms.Valid},
|
||
|
|
"rsaEncryption": {luis, cmstest.Options{}, cms.Valid},
|
||
|
|
"rsaEncryption without parameters": {luis, cmstest.Options{SigAlg: alg(cmstest.OIDRSA)}, cms.Valid},
|
||
|
|
"rsaEncryption with an INTEGER": {luis, cmstest.Options{SigAlg: alg(cmstest.OIDRSA, cmstest.Int(0))}, cms.NotVerifiable},
|
||
|
|
"rsaEncryption with SHA-512": {luis, cmstest.Options{Hash: crypto.SHA512}, cms.Valid},
|
||
|
|
"sha256WithRSAEncryption": {luis, cmstest.Options{SigAlg: alg(cmstest.OIDSHA256RSA, null())}, cms.Valid},
|
||
|
|
"sha256WithRSAEncryption without NULL": {luis, cmstest.Options{SigAlg: alg(cmstest.OIDSHA256RSA)}, cms.Valid},
|
||
|
|
"sha256WithRSAEncryption, INTEGER": {luis, cmstest.Options{SigAlg: alg(cmstest.OIDSHA256RSA, cmstest.Int(0))}, cms.NotVerifiable},
|
||
|
|
"sha256WithRSAEncryption, SHA-384": {luis, cmstest.Options{Hash: crypto.SHA384, SigAlg: alg(cmstest.OIDSHA256RSA, null())}, cms.NotVerifiable},
|
||
|
|
"sha384WithRSAEncryption": {luis, cmstest.Options{Hash: crypto.SHA384, SigAlg: alg(cmstest.OIDSHA384RSA, null())}, cms.Valid},
|
||
|
|
"sha384WithRSAEncryption, SHA-256": {luis, cmstest.Options{SigAlg: alg(cmstest.OIDSHA384RSA, null())}, cms.NotVerifiable},
|
||
|
|
"sha384WithRSAEncryption, INTEGER": {luis, cmstest.Options{Hash: crypto.SHA384, SigAlg: alg(cmstest.OIDSHA384RSA, cmstest.Int(0))}, cms.NotVerifiable},
|
||
|
|
"sha512WithRSAEncryption": {luis, cmstest.Options{Hash: crypto.SHA512, SigAlg: alg(cmstest.OIDSHA512RSA, null())}, cms.Valid},
|
||
|
|
"sha512WithRSAEncryption, SHA-256": {luis, cmstest.Options{SigAlg: alg(cmstest.OIDSHA512RSA, null())}, cms.NotVerifiable},
|
||
|
|
"sha512WithRSAEncryption, INTEGER": {luis, cmstest.Options{Hash: crypto.SHA512, SigAlg: alg(cmstest.OIDSHA512RSA, cmstest.Int(0))}, cms.NotVerifiable},
|
||
|
|
"ecdsa-with-SHA256 with NULL": {ana, cmstest.Options{SigAlg: alg(cmstest.OIDECDSA256, null())}, cms.NotVerifiable},
|
||
|
|
"ecdsa-with-SHA256, SHA-384": {ana, cmstest.Options{Hash: crypto.SHA384, SigAlg: alg(cmstest.OIDECDSA256)}, cms.NotVerifiable},
|
||
|
|
"ecdsa-with-SHA384, SHA-256": {ana, cmstest.Options{SigAlg: alg(cmstest.OIDECDSA384)}, cms.NotVerifiable},
|
||
|
|
"ecdsa-with-SHA384 with NULL": {ana, cmstest.Options{Hash: crypto.SHA384, SigAlg: alg(cmstest.OIDECDSA384, null())}, cms.NotVerifiable},
|
||
|
|
"ecdsa-with-SHA512, SHA-256": {ana, cmstest.Options{SigAlg: alg(cmstest.OIDECDSA512)}, cms.NotVerifiable},
|
||
|
|
"ecdsa-with-SHA512 with NULL": {ana, cmstest.Options{Hash: crypto.SHA512, SigAlg: alg(cmstest.OIDECDSA512, null())}, cms.NotVerifiable},
|
||
|
|
"an algorithm outside the table": {ana, cmstest.Options{SigAlg: alg(asn1.ObjectIdentifier{1, 3, 101, 112})}, cms.NotVerifiable},
|
||
|
|
"another algorithm, an RSA key": {luis, cmstest.Options{SigAlg: alg(asn1.ObjectIdentifier{1, 3, 101, 112})}, cms.NotVerifiable},
|
||
|
|
"another algorithm with PSS parameters": {luis, cmstest.Options{PSS: true, SigAlg: alg(asn1.ObjectIdentifier{1, 2, 3, 4}, cmstest.Seq(h0, m1, s2))}, cms.NotVerifiable},
|
||
|
|
"PSS": {luis, cmstest.Options{PSS: true}, cms.Valid},
|
||
|
|
"PSS with SHA-384": {luis, cmstest.Options{PSS: true, Hash: crypto.SHA384}, cms.Valid},
|
||
|
|
"PSS, its fields written again": {luis, cmstest.Options{PSS: true, SigAlg: pss(h0, m1, s2)}, cms.Valid},
|
||
|
|
"PSS with NULL in its hashes": {luis, cmstest.Options{PSS: true, SigAlg: pss(cmstest.TLV(0xa0, alg(cmstest.OIDSHA256, null())), cmstest.TLV(0xa1, alg(cmstest.OIDMGF1, alg(cmstest.OIDSHA256, null()))), s2)}, cms.Valid},
|
||
|
|
"PSS without parameters": {luis, cmstest.Options{PSS: true, SigAlg: alg(cmstest.OIDPSS)}, cms.NotVerifiable},
|
||
|
|
"PSS with NULL parameters": {luis, cmstest.Options{PSS: true, SigAlg: alg(cmstest.OIDPSS, null())}, cms.NotVerifiable},
|
||
|
|
"PSS parameters as a SET": {luis, cmstest.Options{PSS: true, SigAlg: alg(cmstest.OIDPSS, cmstest.TLV(0x31, h0, m1, s2))}, cms.NotVerifiable},
|
||
|
|
"PSS with [0] of two elements": {luis, cmstest.Options{PSS: true, SigAlg: pss(cmstest.TLV(0xa0, cmstest.HashAlg(crypto.SHA256), null()), m1, s2)}, cms.NotVerifiable},
|
||
|
|
"PSS with [0] primitive": {luis, cmstest.Options{PSS: true, SigAlg: pss(cmstest.TLV(0x80, cmstest.HashAlg(crypto.SHA256)), m1, s2)}, cms.NotVerifiable},
|
||
|
|
"PSS with [1] before [0]": {luis, cmstest.Options{PSS: true, SigAlg: pss(m1, h0, s2)}, cms.NotVerifiable},
|
||
|
|
"PSS with [0] twice": {luis, cmstest.Options{PSS: true, SigAlg: pss(h0, h0, m1, s2)}, cms.NotVerifiable},
|
||
|
|
"PSS of SHA-512 with SHA-256": {luis, cmstest.Options{PSS: true, SigAlg: pss(cmstest.TLV(0xa0, cmstest.HashAlg(crypto.SHA512)), m1, s2)}, cms.NotVerifiable},
|
||
|
|
"PSS with a hash of an INTEGER": {luis, cmstest.Options{PSS: true, SigAlg: pss(cmstest.TLV(0xa0, alg(cmstest.OIDSHA256, cmstest.Int(0))), m1, s2)}, cms.NotVerifiable},
|
||
|
|
"PSS with a hash without an OID": {luis, cmstest.Options{PSS: true, SigAlg: pss(cmstest.TLV(0xa0, cmstest.Seq(cmstest.Int(0))), m1, s2)}, cms.NotVerifiable},
|
||
|
|
"PSS with another mask": {luis, cmstest.Options{PSS: true, SigAlg: pss(h0, cmstest.TLV(0xa1, alg(asn1.ObjectIdentifier{1, 2, 840, 113549, 1, 1, 9}, cmstest.HashAlg(crypto.SHA256))), s2)}, cms.NotVerifiable},
|
||
|
|
"PSS with MGF1 without its hash": {luis, cmstest.Options{PSS: true, SigAlg: pss(h0, cmstest.TLV(0xa1, alg(cmstest.OIDMGF1)), s2)}, cms.NotVerifiable},
|
||
|
|
"PSS with MGF1 not an algorithm": {luis, cmstest.Options{PSS: true, SigAlg: pss(h0, cmstest.TLV(0xa1, cmstest.Seq(cmstest.Int(1))), s2)}, cms.NotVerifiable},
|
||
|
|
"PSS with MGF1 of SHA-512": {luis, cmstest.Options{PSS: true, SigAlg: pss(h0, cmstest.TLV(0xa1, alg(cmstest.OIDMGF1, cmstest.HashAlg(crypto.SHA512))), s2)}, cms.NotVerifiable},
|
||
|
|
"PSS with MGF1 of a hash with INTEGER": {luis, cmstest.Options{PSS: true, SigAlg: pss(h0, cmstest.TLV(0xa1, alg(cmstest.OIDMGF1, alg(cmstest.OIDSHA256, cmstest.Int(0)))), s2)}, cms.NotVerifiable},
|
||
|
|
"PSS with MGF1 of a hash without OID": {luis, cmstest.Options{PSS: true, SigAlg: pss(h0, cmstest.TLV(0xa1, alg(cmstest.OIDMGF1, cmstest.Seq(cmstest.Int(0)))), s2)}, cms.NotVerifiable},
|
||
|
|
"PSS with a salt of 20": {luis, cmstest.Options{PSS: true, SigAlg: pss(h0, m1, cmstest.TLV(0xa2, cmstest.Int(20)))}, cms.NotVerifiable},
|
||
|
|
"PSS with a salt in OCTETS": {luis, cmstest.Options{PSS: true, SigAlg: pss(h0, m1, cmstest.TLV(0xa2, cmstest.Octets([]byte{32})))}, cms.NotVerifiable},
|
||
|
|
"PSS with a salt of 2^64 + 32": {luis, cmstest.Options{PSS: true, SigAlg: pss(h0, m1, cmstest.TLV(0xa2, cmstest.IntBytes([]byte{1, 0, 0, 0, 0, 0, 0, 0, 32})))}, cms.NotVerifiable},
|
||
|
|
"PSS with a negative salt": {luis, cmstest.Options{PSS: true, SigAlg: pss(h0, m1, cmstest.TLV(0xa2, cmstest.Int(-224)))}, cms.NotVerifiable},
|
||
|
|
"PSS with trailerField": {luis, cmstest.Options{PSS: true, PSSTrailer: true}, cms.NotVerifiable},
|
||
|
|
"PSS with a field [4]": {luis, cmstest.Options{PSS: true, SigAlg: pss(h0, m1, s2, cmstest.TLV(0xa4, cmstest.Int(1)))}, cms.NotVerifiable},
|
||
|
|
"PSS without [0]": {luis, cmstest.Options{PSS: true, SigAlg: pss(m1, s2)}, cms.NotVerifiable},
|
||
|
|
"PSS without [1]": {luis, cmstest.Options{PSS: true, SigAlg: pss(h0, s2)}, cms.NotVerifiable},
|
||
|
|
"PSS without [2]": {luis, cmstest.Options{PSS: true, SigAlg: pss(h0, m1)}, cms.NotVerifiable},
|
||
|
|
"step 3: an RSA key with ECDSA": {luis, cmstest.Options{SigAlg: alg(cmstest.OIDECDSA256)}, cms.Invalid},
|
||
|
|
"step 3: an EC key with PKCS #1": {ana, cmstest.Options{SigAlg: alg(cmstest.OIDRSA, null())}, cms.Invalid},
|
||
|
|
"step 3: an EC key with PSS": {ana, cmstest.Options{SigAlg: pss(h0, m1, s2)}, cms.Invalid},
|
||
|
|
"step 3: PKCS #1, a bit flipped": {luis, cmstest.Options{CorruptSignature: true}, cms.Invalid},
|
||
|
|
"step 3: PSS, a bit flipped": {luis, cmstest.Options{PSS: true, CorruptSignature: true}, cms.Invalid},
|
||
|
|
"step 3: ECDSA, a bit flipped": {ana, cmstest.Options{CorruptSignature: true}, cms.Invalid},
|
||
|
|
"step 3: the digest of another message": {ana, cmstest.Options{Message: []byte("other")}, cms.Invalid},
|
||
|
|
} {
|
||
|
|
if got := resultOf(t, name, cmstest.Signature(msg, tc.o, tc.s)); got != tc.want {
|
||
|
|
t.Errorf("%s: %v, want %v", name, got, tc.want)
|
||
|
|
}
|
||
|
|
}
|
||
|
|
}
|
||
|
|
|
||
|
|
// The keys of the table (spec §29.10): RSA with NULL parameters, exactly a
|
||
|
|
// modulus and an exponent, the modulus odd of 2048 to 4096 bits and the
|
||
|
|
// exponent odd from 3 to 2^31 - 1; EC on P-256, P-384 or P-521, the point
|
||
|
|
// uncompressed and on the curve. Any other is not verifiable; a key of the
|
||
|
|
// table that does not verify the signature is invalid.
|
||
|
|
func TestKeyTable(t *testing.T) {
|
||
|
|
n, e := rsaKey.N, big.NewInt(65537)
|
||
|
|
two := func(bits uint) *big.Int {
|
||
|
|
return new(big.Int).Add(new(big.Int).Lsh(big.NewInt(1), bits), big.NewInt(1))
|
||
|
|
}
|
||
|
|
key := func(fields ...[]byte) []byte { return cmstest.BitString(cmstest.Seq(fields...)) }
|
||
|
|
rsaAlg := cmstest.AlgID(cmstest.OIDRSA, cmstest.Null())
|
||
|
|
ecAlg := cmstest.AlgID(cmstest.OIDECPublicKey, cmstest.OID(cmstest.OIDP256))
|
||
|
|
point := cmstest.Uncompressed(&ecKey.PublicKey)
|
||
|
|
off := bytes.Clone(point)
|
||
|
|
off[len(off)-1] ^= 1
|
||
|
|
even := evenPointKey()
|
||
|
|
evenPoint := cmstest.Uncompressed(&even.PublicKey)
|
||
|
|
for name, tc := range map[string]struct {
|
||
|
|
spki []byte
|
||
|
|
key crypto.Signer
|
||
|
|
want cms.Result
|
||
|
|
}{
|
||
|
|
"RSA of 2048 bits": {cmstest.SPKIRSA(n, e), rsaKey, cms.Valid},
|
||
|
|
"RSA of 2047 bits": {cmstest.SPKIRSA(two(2046), e), rsaKey, cms.NotVerifiable},
|
||
|
|
"RSA of 4096 bits that is another": {cmstest.SPKIRSA(two(4095), e), rsaKey, cms.Invalid},
|
||
|
|
"RSA of 4097 bits": {cmstest.SPKIRSA(two(4096), e), rsaKey, cms.NotVerifiable},
|
||
|
|
"an even modulus": {cmstest.SPKIRSA(new(big.Int).Add(n, big.NewInt(1)), e), rsaKey, cms.NotVerifiable},
|
||
|
|
"a negative modulus": {cmstest.SPKIRSA(new(big.Int).Neg(n), e), rsaKey, cms.NotVerifiable},
|
||
|
|
"an exponent of 1": {cmstest.SPKIRSA(n, big.NewInt(1)), rsaKey, cms.NotVerifiable},
|
||
|
|
"an exponent of 3": {cmstest.SPKIRSA(n, big.NewInt(3)), rsaKey, cms.Invalid},
|
||
|
|
"an even exponent": {cmstest.SPKIRSA(n, big.NewInt(65536)), rsaKey, cms.NotVerifiable},
|
||
|
|
"an exponent of 2^31 - 1": {cmstest.SPKIRSA(n, big.NewInt(1<<31-1)), rsaKey, cms.Invalid},
|
||
|
|
"an exponent of 2^64 + 65537": {cmstest.SPKIRSA(n, new(big.Int).Add(new(big.Int).Lsh(big.NewInt(1), 64), e)), rsaKey, cms.NotVerifiable},
|
||
|
|
"a negative exponent": {cmstest.SPKIRSA(n, big.NewInt(-1)), rsaKey, cms.NotVerifiable},
|
||
|
|
"an RSAPublicKey with a byte more": {cmstest.Seq(rsaAlg, cmstest.BitString(append(cmstest.Seq(cmstest.BigInt(n), cmstest.BigInt(e)), 0))), rsaKey, cms.NotVerifiable},
|
||
|
|
"an RSAPublicKey as a SET": {cmstest.Seq(rsaAlg, cmstest.BitString(cmstest.TLV(0x31, cmstest.BigInt(n), cmstest.BigInt(e)))), rsaKey, cms.NotVerifiable},
|
||
|
|
"an RSAPublicKey of three INTEGERs": {cmstest.Seq(rsaAlg, key(cmstest.BigInt(n), cmstest.BigInt(e), cmstest.Int(1))), rsaKey, cms.NotVerifiable},
|
||
|
|
"an RSAPublicKey that is an INTEGER": {cmstest.Seq(rsaAlg, cmstest.BitString(cmstest.BigInt(n))), rsaKey, cms.NotVerifiable},
|
||
|
|
"a modulus in OCTETS": {cmstest.Seq(rsaAlg, key(cmstest.Octets(append([]byte{0}, n.Bytes()...)), cmstest.BigInt(e))), rsaKey, cms.NotVerifiable},
|
||
|
|
"an exponent in OCTETS": {cmstest.Seq(rsaAlg, key(cmstest.BigInt(n), cmstest.Octets(e.Bytes()))), rsaKey, cms.NotVerifiable},
|
||
|
|
"rsaEncryption without NULL": {cmstest.Seq(cmstest.AlgID(cmstest.OIDRSA), key(cmstest.BigInt(n), cmstest.BigInt(e))), rsaKey, cms.NotVerifiable},
|
||
|
|
"an RSA key of id-RSASSA-PSS": {cmstest.Seq(cmstest.AlgID(cmstest.OIDPSS, cmstest.Null()), key(cmstest.BigInt(n), cmstest.BigInt(e))), rsaKey, cms.NotVerifiable},
|
||
|
|
"an SPKI of three elements": {cmstest.Seq(rsaAlg, key(cmstest.BigInt(n), cmstest.BigInt(e)), cmstest.Null()), rsaKey, cms.NotVerifiable},
|
||
|
|
"an SPKI whose key is OCTETS": {cmstest.Seq(rsaAlg, cmstest.Octets(append([]byte{0}, cmstest.Seq(cmstest.BigInt(n), cmstest.BigInt(e))...))), rsaKey, cms.NotVerifiable},
|
||
|
|
"an SPKI whose algorithm is a SET": {cmstest.Seq(cmstest.TLV(0x31, cmstest.OID(cmstest.OIDRSA), cmstest.Null()), key(cmstest.BigInt(n), cmstest.BigInt(e))), rsaKey, cms.NotVerifiable},
|
||
|
|
"an SPKI of no algorithm": {cmstest.Seq(cmstest.Seq(cmstest.Int(1)), key(cmstest.BigInt(n), cmstest.BigInt(e))), rsaKey, cms.NotVerifiable},
|
||
|
|
"P-256": {cmstest.SPKIEC(cmstest.OID(cmstest.OIDP256), point), ecKey, cms.Valid},
|
||
|
|
"a compressed point": {cmstest.SPKICompressed(&ecKey.PublicKey), ecKey, cms.NotVerifiable},
|
||
|
|
"a point off the curve": {cmstest.SPKIEC(cmstest.OID(cmstest.OIDP256), off), ecKey, cms.NotVerifiable},
|
||
|
|
"a point of P-256 said P-384": {cmstest.SPKIEC(cmstest.OID(cmstest.OIDP384), point), ecKey, cms.NotVerifiable},
|
||
|
|
"brainpoolP256r1": {cmstest.SPKIEC(cmstest.OID(cmstest.OIDBrainpoolP256), point), ecKey, cms.NotVerifiable},
|
||
|
|
"a point of P-521, another curve": {cmstest.SPKIEC(cmstest.OID(cmstest.OIDBrainpoolP256), cmstest.Uncompressed(&p521Key.PublicKey)), p521Key, cms.NotVerifiable},
|
||
|
|
"id-ecPublicKey without a curve": {cmstest.Seq(cmstest.AlgID(cmstest.OIDECPublicKey), cmstest.BitString(point)), ecKey, cms.NotVerifiable},
|
||
|
|
"id-ecPublicKey with NULL": {cmstest.SPKIEC(cmstest.Null(), point), ecKey, cms.NotVerifiable},
|
||
|
|
"an EC key of id-ecDH": {cmstest.Seq(cmstest.AlgID(asn1.ObjectIdentifier{1, 3, 132, 1, 12}, cmstest.OID(cmstest.OIDP256)), cmstest.BitString(point)), ecKey, cms.NotVerifiable},
|
||
|
|
"a BIT STRING of 1 unused bit": {cmstest.Seq(ecAlg, cmstest.TLV(0x03, append([]byte{1}, evenPoint...))), even, cms.NotVerifiable},
|
||
|
|
"an empty BIT STRING": {cmstest.Seq(ecAlg, cmstest.TLV(0x03, []byte{0})), ecKey, cms.NotVerifiable},
|
||
|
|
} {
|
||
|
|
s := cmstest.NewCert(cmstest.CertSpec{CN: "Clave", SPKI: tc.spki}, tc.key)
|
||
|
|
if got := resultOf(t, name, cmstest.Signature(msg, cmstest.Options{}, s)); got != tc.want {
|
||
|
|
t.Errorf("%s: %v, want %v", name, got, tc.want)
|
||
|
|
}
|
||
|
|
}
|
||
|
|
}
|
||
|
|
|
||
|
|
// evenPointKey returns a P-256 key whose point ends in an even byte: a BIT
|
||
|
|
// STRING with one unused bit holds it in DER.
|
||
|
|
func evenPointKey() *ecdsa.PrivateKey {
|
||
|
|
for {
|
||
|
|
k := cmstest.ECKey(elliptic.P256())
|
||
|
|
if p := cmstest.Uncompressed(&k.PublicKey); p[len(p)-1]&1 == 0 {
|
||
|
|
return k
|
||
|
|
}
|
||
|
|
}
|
||
|
|
}
|
||
|
|
|
||
|
|
// Spec §29.11: the token in the order of its profile, form (S2), algorithms
|
||
|
|
// (S1) and verification (S3).
|
||
|
|
func TestTokenProfile(t *testing.T) {
|
||
|
|
subject := []byte("seal subject")
|
||
|
|
tok := func(o cmstest.TokenOptions, s cmstest.Signer) []byte { return cmstest.Token(subject, now, o, s) }
|
||
|
|
small := cmstest.NewCert(cmstest.CertSpec{CN: "TSA 1024"}, cmstest.RSAKey(1024))
|
||
|
|
compressed := cmstest.NewCert(cmstest.CertSpec{CN: "TSA comprimida", SPKI: cmstest.SPKICompressed(&ecKey2.PublicKey)}, ecKey2)
|
||
|
|
notYet := cmstest.NewCert(cmstest.CertSpec{CN: "TSA futura", From: now.Add(time.Second)}, ecKey2)
|
||
|
|
expired := cmstest.NewCert(cmstest.CertSpec{CN: "TSA caducada", To: now.Add(-time.Second)}, ecKey2)
|
||
|
|
exact := cmstest.NewCert(cmstest.CertSpec{CN: "TSA justa", From: now, To: now}, ecKey2)
|
||
|
|
badImprintAlg := func() []byte {
|
||
|
|
info := cmstest.Seq(cmstest.Int(1), cmstest.OID(asn1.ObjectIdentifier{1, 2, 3, 4}), cmstest.Seq(cmstest.Seq(cmstest.Int(1)), cmstest.Octets(make([]byte, 32))), cmstest.Int(42), cmstest.GeneralizedTimeOf(now))
|
||
|
|
return cmstest.TokenRaw(info, tsa)
|
||
|
|
}
|
||
|
|
for name, tc := range map[string]struct {
|
||
|
|
token []byte
|
||
|
|
form bool // S2, else S1
|
||
|
|
}{
|
||
|
|
"S1: an imprint of SHA-1": {tok(cmstest.TokenOptions{Hash: crypto.SHA1}, tsa), false},
|
||
|
|
"S1: a signature of SHA-1": {tok(cmstest.TokenOptions{CMS: cmstest.Options{Hash: crypto.SHA1}}, tsa), false},
|
||
|
|
"S1: a key of 1024 bits": {tok(cmstest.TokenOptions{}, small), false},
|
||
|
|
"S1: a compressed key": {tok(cmstest.TokenOptions{}, compressed), false},
|
||
|
|
"S1: PSS with trailerField": {tok(cmstest.TokenOptions{CMS: cmstest.Options{PSS: true, PSSTrailer: true}}, luis), false},
|
||
|
|
"S2 before S1: SHA-1 and version 2": {tok(cmstest.TokenOptions{Hash: crypto.SHA1, Version: 2}, tsa), true},
|
||
|
|
"S2 before S1: SHA-1 and no digest": {tok(cmstest.TokenOptions{Hash: crypto.SHA1, NoMessageDigest: true}, tsa), true},
|
||
|
|
"S2: an imprint algorithm that is no one": {badImprintAlg(), true},
|
||
|
|
} {
|
||
|
|
_, err := cms.ParseToken(tc.token)
|
||
|
|
if tc.form && !isForm(err) || !tc.form && !isAlgorithm(err) {
|
||
|
|
t.Errorf("%s: %v", name, err)
|
||
|
|
}
|
||
|
|
}
|
||
|
|
// S3: it reads, and does not verify.
|
||
|
|
for name, b := range map[string][]byte{
|
||
|
|
"the signature of the authority, a bit flipped": tok(cmstest.TokenOptions{CMS: cmstest.Options{CorruptSignature: true}}, tsa),
|
||
|
|
"the message-digest of another TSTInfo": tok(cmstest.TokenOptions{CMS: cmstest.Options{Message: []byte("other")}}, tsa),
|
||
|
|
"an imprint of 33 bytes": tok(cmstest.TokenOptions{Imprint: append(sha256Of(subject), 0)}, tsa),
|
||
|
|
"an imprint of 31 bytes": tok(cmstest.TokenOptions{Imprint: sha256Of(subject)[:31]}, tsa),
|
||
|
|
"another imprint": tok(cmstest.TokenOptions{Imprint: make([]byte, 32)}, tsa),
|
||
|
|
"an authority not yet valid": tok(cmstest.TokenOptions{}, notYet),
|
||
|
|
"an authority expired": tok(cmstest.TokenOptions{}, expired),
|
||
|
|
"an authority of PSS, a bit flipped": tok(cmstest.TokenOptions{CMS: cmstest.Options{PSS: true, CorruptSignature: true}}, luis),
|
||
|
|
} {
|
||
|
|
token, err := cms.ParseToken(b)
|
||
|
|
if err != nil || token.Check(subject) {
|
||
|
|
t.Errorf("%s: %v, valid %v", name, err, err == nil && token.Check(subject))
|
||
|
|
}
|
||
|
|
}
|
||
|
|
// Valid: at the first and the last instant of the validity of the
|
||
|
|
// authority, with RSA, PSS and SHA-512, and with the imprint of SHA-384,
|
||
|
|
// which only seal_type 2 refuses.
|
||
|
|
for name, b := range map[string][]byte{
|
||
|
|
"an authority valid exactly then": tok(cmstest.TokenOptions{}, exact),
|
||
|
|
"an authority of RSA": tok(cmstest.TokenOptions{}, luis),
|
||
|
|
"an authority of PSS": tok(cmstest.TokenOptions{CMS: cmstest.Options{PSS: true}}, luis),
|
||
|
|
"a signature of SHA-512": tok(cmstest.TokenOptions{CMS: cmstest.Options{Hash: crypto.SHA512}}, tsa),
|
||
|
|
} {
|
||
|
|
token, err := cms.ParseToken(b)
|
||
|
|
if err != nil || !token.Check(subject) || !token.ImprintIsSHA256() {
|
||
|
|
t.Errorf("%s: %v", name, err)
|
||
|
|
}
|
||
|
|
}
|
||
|
|
token, err := cms.ParseToken(tok(cmstest.TokenOptions{Hash: crypto.SHA384}, tsa))
|
||
|
|
if err != nil || !token.Check(subject) || token.ImprintIsSHA256() {
|
||
|
|
t.Errorf("an imprint of SHA-384: %v", err)
|
||
|
|
}
|
||
|
|
}
|
||
|
|
|
||
|
|
func sha256Of(b []byte) []byte {
|
||
|
|
h := crypto.SHA256.New()
|
||
|
|
h.Write(b)
|
||
|
|
return h.Sum(nil)
|
||
|
|
}
|