local-server/vendor/github.com/cloudflare/cfssl/helpers/helpers_test.go
Mikaël Cluseau 4d889632f6 vendor
2018-06-17 18:32:44 +11:00

630 lines
17 KiB
Go

package helpers
import (
"bytes"
"crypto/ecdsa"
"crypto/elliptic"
"crypto/rand"
"crypto/rsa"
"crypto/x509"
"crypto/x509/pkix"
"encoding/asn1"
"encoding/pem"
"io/ioutil"
"math"
"testing"
"time"
"golang.org/x/crypto/ocsp"
"github.com/google/certificate-transparency-go"
)
const (
testCertFile = "testdata/cert.pem"
testCertDERFile = "testdata/cert.der"
testBundleFile = "testdata/bundle.pem"
testExtraWSCertFile = "testdata/cert_with_whitespace.pem"
testExtraWSBundleFile = "testdata/bundle_with_whitespace.pem"
testMessedUpBundleFile = "testdata/messed_up_bundle.pem"
testMessedUpCertFile = "testdata/messedupcert.pem"
testEmptyCertFile = "testdata/emptycert.pem"
testPrivateRSAKey = "testdata/priv_rsa_key.pem"
testPrivateECDSAKey = "testdata/private_ecdsa_key.pem"
testUnsupportedECDSAKey = "testdata/secp256k1-key.pem"
testMessedUpPrivateKey = "testdata/messed_up_priv_key.pem"
testEncryptedPrivateKey = "testdata/enc_priv_key.pem"
testEmptyPem = "testdata/empty.pem"
testNoHeaderCert = "testdata/noheadercert.pem"
testSinglePKCS7 = "testdata/cert_pkcs7.pem" // openssl crl2pkcs7 -nocrl -out cert_pkcs7.pem -in cert.pem
testEmptyPKCS7DER = "testdata/empty_pkcs7.der" // openssl crl2pkcs7 -nocrl -out empty_pkcs7.der -outform der
testEmptyPKCS7PEM = "testdata/empty_pkcs7.pem" // openssl crl2pkcs7 -nocrl -out empty_pkcs7.pem -outform pem
testMultiplePKCS7 = "testdata/bundle_pkcs7.pem"
testPKCS12EmptyPswd = "testdata/emptypasswordpkcs12.p12"
testPKCS12Passwordispassword = "testdata/passwordpkcs12.p12"
testPKCS12MultipleCerts = "testdata/multiplecerts.p12"
testCSRPEM = "testdata/test.csr.pem"
testCSRPEMBad = "testdata/test.bad.csr.pem"
)
func TestParseCertificatesDER(t *testing.T) {
var password = []string{"password", "", ""}
for i, testFile := range []string{testPKCS12Passwordispassword, testPKCS12EmptyPswd, testCertDERFile} {
testDER, err := ioutil.ReadFile(testFile)
if err != nil {
t.Fatal(err)
}
if _, _, err := ParseCertificatesDER(testDER, password[i]); err != nil {
t.Fatal(err)
}
// Incorrect Password for PKCS12 formatted files
if _, _, err := ParseCertificatesDER(testDER, "incorrectpassword"); err == nil && i != 2 {
t.Fatal(err)
}
}
testDER, err := ioutil.ReadFile(testEmptyPKCS7DER)
if err != nil {
t.Fatal(err)
}
// PKCS7 with no certificates
if _, _, err := ParseCertificatesDER(testDER, ""); err == nil {
t.Fatal(err)
}
}
func TestKeyLength(t *testing.T) {
expNil := 0
recNil := KeyLength(nil)
if expNil != recNil {
t.Fatal("KeyLength on nil did not return 0")
}
expNonsense := 0
inNonsense := "string?"
outNonsense := KeyLength(inNonsense)
if expNonsense != outNonsense {
t.Fatal("KeyLength malfunctioning on nonsense input")
}
//test the ecdsa branch
ecdsaPriv, _ := ecdsa.GenerateKey(elliptic.P224(), rand.Reader)
ecdsaIn, _ := ecdsaPriv.Public().(*ecdsa.PublicKey)
expEcdsa := ecdsaIn.Curve.Params().BitSize
outEcdsa := KeyLength(ecdsaIn)
if expEcdsa != outEcdsa {
t.Fatal("KeyLength malfunctioning on ecdsa input")
}
//test the rsa branch
rsaPriv, _ := rsa.GenerateKey(rand.Reader, 256)
rsaIn, _ := rsaPriv.Public().(*rsa.PublicKey)
expRsa := rsaIn.N.BitLen()
outRsa := KeyLength(rsaIn)
if expRsa != outRsa {
t.Fatal("KeyLength malfunctioning on rsa input")
}
}
func TestExpiryTime(t *testing.T) {
// nil case
var expNil time.Time
inNil := []*x509.Certificate{}
outNil := ExpiryTime(inNil)
if expNil != outNil {
t.Fatal("Expiry time is malfunctioning on empty input")
}
//read a pem file and use that expiry date
bytes, _ := ioutil.ReadFile(testBundleFile)
certs, err := ParseCertificatesPEM(bytes)
if err != nil {
t.Fatalf("%v", err)
}
expected := time.Date(2014, time.April, 15, 0, 0, 0, 0, time.UTC)
out := ExpiryTime(certs)
if out != expected {
t.Fatalf("Expected %v, got %v", expected, out)
}
}
func TestMonthsValid(t *testing.T) {
var cert = &x509.Certificate{
NotBefore: time.Date(2015, time.April, 01, 0, 0, 0, 0, time.UTC),
NotAfter: time.Date(2015, time.April, 01, 0, 0, 0, 0, time.UTC),
}
if MonthsValid(cert) != 0 {
t.Fail()
}
cert.NotAfter = time.Date(2016, time.April, 01, 0, 0, 0, 0, time.UTC)
if MonthsValid(cert) != 12 {
t.Fail()
}
// extra days should be rounded up to 1 month
cert.NotAfter = time.Date(2016, time.April, 02, 0, 0, 0, 0, time.UTC)
if MonthsValid(cert) != 13 {
t.Fail()
}
}
func TestHasValidExpiry(t *testing.T) {
// Issue period > April 1, 2015
var cert = &x509.Certificate{
NotBefore: time.Date(2015, time.April, 01, 0, 0, 0, 0, time.UTC),
NotAfter: time.Date(2016, time.April, 01, 0, 0, 0, 0, time.UTC),
}
if !ValidExpiry(cert) {
t.Fail()
}
cert.NotAfter = time.Date(2019, time.April, 01, 01, 0, 0, 0, time.UTC)
if ValidExpiry(cert) {
t.Fail()
}
// Issue period < July 1, 2012
cert.NotBefore = time.Date(2009, time.March, 01, 0, 0, 0, 0, time.UTC)
if ValidExpiry(cert) {
t.Fail()
}
// Issue period July 1, 2012 - April 1, 2015
cert.NotBefore = time.Date(2012, time.July, 01, 0, 0, 0, 0, time.UTC)
cert.NotAfter = time.Date(2017, time.July, 01, 0, 0, 0, 0, time.UTC)
if !ValidExpiry(cert) {
t.Fail()
}
}
func TestHashAlgoString(t *testing.T) {
if HashAlgoString(x509.MD2WithRSA) != "MD2" {
t.Fatal("standin")
}
if HashAlgoString(x509.MD5WithRSA) != "MD5" {
t.Fatal("standin")
}
if HashAlgoString(x509.SHA1WithRSA) != "SHA1" {
t.Fatal("standin")
}
if HashAlgoString(x509.SHA256WithRSA) != "SHA256" {
t.Fatal("standin")
}
if HashAlgoString(x509.SHA384WithRSA) != "SHA384" {
t.Fatal("standin")
}
if HashAlgoString(x509.SHA512WithRSA) != "SHA512" {
t.Fatal("standin")
}
if HashAlgoString(x509.DSAWithSHA1) != "SHA1" {
t.Fatal("standin")
}
if HashAlgoString(x509.DSAWithSHA256) != "SHA256" {
t.Fatal("standin")
}
if HashAlgoString(x509.ECDSAWithSHA1) != "SHA1" {
t.Fatal("standin")
}
if HashAlgoString(x509.ECDSAWithSHA256) != "SHA256" {
t.Fatal("standin")
}
if HashAlgoString(x509.ECDSAWithSHA384) != "SHA384" {
t.Fatal("standin")
}
if HashAlgoString(x509.ECDSAWithSHA512) != "SHA512" {
t.Fatal("standin")
}
if HashAlgoString(math.MaxInt32) != "Unknown Hash Algorithm" {
t.Fatal("standin")
}
}
func TestSignatureString(t *testing.T) {
if SignatureString(x509.MD2WithRSA) != "MD2WithRSA" {
t.Fatal("Signature String functioning improperly")
}
if SignatureString(x509.MD5WithRSA) != "MD5WithRSA" {
t.Fatal("Signature String functioning improperly")
}
if SignatureString(x509.SHA1WithRSA) != "SHA1WithRSA" {
t.Fatal("Signature String functioning improperly")
}
if SignatureString(x509.SHA256WithRSA) != "SHA256WithRSA" {
t.Fatal("Signature String functioning improperly")
}
if SignatureString(x509.SHA384WithRSA) != "SHA384WithRSA" {
t.Fatal("Signature String functioning improperly")
}
if SignatureString(x509.SHA512WithRSA) != "SHA512WithRSA" {
t.Fatal("Signature String functioning improperly")
}
if SignatureString(x509.DSAWithSHA1) != "DSAWithSHA1" {
t.Fatal("Signature String functioning improperly")
}
if SignatureString(x509.DSAWithSHA256) != "DSAWithSHA256" {
t.Fatal("Signature String functioning improperly")
}
if SignatureString(x509.ECDSAWithSHA1) != "ECDSAWithSHA1" {
t.Fatal("Signature String functioning improperly")
}
if SignatureString(x509.ECDSAWithSHA256) != "ECDSAWithSHA256" {
t.Fatal("Signature String functioning improperly")
}
if SignatureString(x509.ECDSAWithSHA384) != "ECDSAWithSHA384" {
t.Fatal("Signature String functioning improperly")
}
if SignatureString(x509.ECDSAWithSHA512) != "ECDSAWithSHA512" {
t.Fatal("Signature String functioning improperly")
}
if SignatureString(math.MaxInt32) != "Unknown Signature" {
t.Fatal("Signature String functioning improperly")
}
}
func TestParseCertificatePEM(t *testing.T) {
for _, testFile := range []string{testCertFile, testExtraWSCertFile, testSinglePKCS7} {
certPEM, err := ioutil.ReadFile(testFile)
if err != nil {
t.Fatal(err)
}
if _, err := ParseCertificatePEM(certPEM); err != nil {
t.Log(testFile)
t.Fatal(err)
}
}
for _, testFile := range []string{testBundleFile, testMessedUpCertFile, testEmptyPKCS7PEM, testEmptyCertFile, testMultiplePKCS7} {
certPEM, err := ioutil.ReadFile(testFile)
if err != nil {
t.Fatal(err)
}
if _, err := ParseCertificatePEM(certPEM); err == nil {
t.Fatal("Incorrect cert failed to raise error")
}
}
}
func TestParseCertificatesPEM(t *testing.T) {
// expected cases
for _, testFile := range []string{testBundleFile, testExtraWSBundleFile, testSinglePKCS7, testMultiplePKCS7} {
bundlePEM, err := ioutil.ReadFile(testFile)
if err != nil {
t.Fatal(err)
}
if _, err := ParseCertificatesPEM(bundlePEM); err != nil {
t.Log(testFile)
t.Fatal(err)
}
}
// test failure cases
// few lines deleted, then headers removed
for _, testFile := range []string{testMessedUpBundleFile, testEmptyPKCS7PEM, testNoHeaderCert} {
bundlePEM, err := ioutil.ReadFile(testFile)
if err != nil {
t.Fatal(err)
}
if _, err := ParseCertificatesPEM(bundlePEM); err == nil {
t.Fatal("Incorrectly-formatted file failed to produce an error")
}
}
}
func TestSelfSignedCertificatePEM(t *testing.T) {
testPEM, _ := ioutil.ReadFile(testCertFile)
_, err := ParseSelfSignedCertificatePEM(testPEM)
if err != nil {
t.Fatalf("%v", err)
}
// a few lines deleted from the pem file
wrongPEM, _ := ioutil.ReadFile(testMessedUpCertFile)
_, err2 := ParseSelfSignedCertificatePEM(wrongPEM)
if err2 == nil {
t.Fatal("Improper pem file failed to raise an error")
}
// alter the signature of a valid certificate
blk, _ := pem.Decode(testPEM)
blk.Bytes[len(blk.Bytes)-10]++ // some hacking to get to the sig
alteredBytes := pem.EncodeToMemory(blk)
_, err = ParseSelfSignedCertificatePEM(alteredBytes)
if err == nil {
t.Fatal("Incorrect cert failed to produce an error")
}
}
func TestParsePrivateKeyPEM(t *testing.T) {
// expected cases
testRSAPEM, _ := ioutil.ReadFile(testPrivateRSAKey)
_, err := ParsePrivateKeyPEM(testRSAPEM)
if err != nil {
t.Fatal(err)
}
testECDSAPEM, _ := ioutil.ReadFile(testPrivateECDSAKey)
_, err = ParsePrivateKeyPEM(testECDSAPEM)
if err != nil {
t.Fatal(err)
}
// error cases
errCases := []string{
testMessedUpPrivateKey, // a few lines deleted
testEmptyPem, // empty file
testEncryptedPrivateKey, // encrypted key
testUnsupportedECDSAKey, // ECDSA curve not currently supported by Go standard library
}
for _, fname := range errCases {
testPEM, _ := ioutil.ReadFile(fname)
_, err = ParsePrivateKeyPEM(testPEM)
if err == nil {
t.Fatal("Incorrect private key failed to produce an error")
}
}
}
// Imported from signers/local/testdata/
const ecdsaTestCSR = "testdata/ecdsa256.csr"
func TestParseCSRPEM(t *testing.T) {
in, err := ioutil.ReadFile(ecdsaTestCSR)
if err != nil {
t.Fatalf("%v", err)
}
_, _, err = ParseCSR(in)
if err != nil {
t.Fatalf("%v", err)
}
in[12]++
_, _, err = ParseCSR(in)
if err == nil {
t.Fatalf("Expected an invalid CSR.")
}
in[12]--
}
func TestParseCSRPEMMore(t *testing.T) {
csrPEM, err := ioutil.ReadFile(testCSRPEM)
if err != nil {
t.Fatal(err)
}
if _, err := ParseCSRPEM(csrPEM); err != nil {
t.Fatal(err)
}
csrPEM, err = ioutil.ReadFile(testCSRPEMBad)
if err != nil {
t.Fatal(err)
}
if _, err := ParseCSRPEM(csrPEM); err == nil {
t.Fatal(err)
}
if _, err := ParseCSRPEM([]byte("not even pem")); err == nil {
t.Fatal("Expected an invalid CSR.")
}
}
// Imported from signers/local/testdata/
const rsaOldTestCSR = "testdata/rsa-old.csr"
func TestParseOldCSR(t *testing.T) {
in, err := ioutil.ReadFile(rsaOldTestCSR)
if err != nil {
t.Fatalf("%v", err)
}
_, _, err = ParseCSR(in)
if err != nil {
t.Fatalf("%v", err)
}
}
// Imported from signers/local/testdata/
const clientCertFile = "testdata/ca.pem"
const clientKeyFile = "testdata/ca_key.pem"
func TestClientCertParams(t *testing.T) {
_, err := LoadClientCertificate(testCertFile, testPrivateRSAKey)
if err == nil {
t.Fatal("Unmatched cert/key should generate error")
}
cert, err := LoadClientCertificate("", "")
if err != nil || cert != nil {
t.Fatal("Certificate atempted to loaded with missing key and cert")
}
cert, err = LoadClientCertificate(clientCertFile, "")
if err != nil || cert != nil {
t.Fatal("Certificate atempted to loaded with missing key")
}
cert, err = LoadClientCertificate("", clientKeyFile)
if err != nil || cert != nil {
t.Fatal("Certificate atempted to loaded with missing cert")
}
cert, err = LoadClientCertificate(clientCertFile, clientKeyFile)
if err != nil {
t.Fatal(err)
}
if cert == nil {
t.Fatal("cert not created")
}
}
func TestLoadPEMCertPool(t *testing.T) {
certPool, err := PEMToCertPool([]byte{})
if certPool != nil || err != nil {
t.Fatal("Empty file name should not generate error or a cert pool")
}
in, err := ioutil.ReadFile(testEmptyPem)
if err != nil {
t.Fatalf("%v", err)
}
certPool, err = PEMToCertPool(in)
if certPool != nil {
t.Fatal("Empty file should not generate a cert pool")
} else if err == nil {
t.Fatal("Expected error for empty file")
}
in, err = ioutil.ReadFile(testEmptyCertFile)
if err != nil {
t.Fatalf("%v", err)
}
certPool, err = PEMToCertPool(in)
if certPool != nil {
t.Fatal("Empty cert should not generate a cert pool")
} else if err == nil {
t.Fatal("Expected error for empty cert")
}
in, err = ioutil.ReadFile(clientCertFile)
if err != nil {
t.Fatalf("%v", err)
}
certPool, err = PEMToCertPool(in)
if err != nil {
t.Fatalf("%v", err)
} else if certPool == nil {
t.Fatal("cert pool not created")
}
}
// sctEquals returns true if all fields of both SCTs are equivalent.
func sctEquals(sctA, sctB ct.SignedCertificateTimestamp) bool {
if sctA.SCTVersion == sctB.SCTVersion &&
sctA.LogID == sctB.LogID &&
sctA.Timestamp == sctB.Timestamp &&
bytes.Equal(sctA.Extensions, sctB.Extensions) &&
sctA.Signature.Algorithm == sctB.Signature.Algorithm &&
bytes.Equal(sctA.Signature.Signature, sctA.Signature.Signature) {
return true
}
return false
}
// NOTE: TestDeserializeSCTList tests both DeserializeSCTList and
// SerializeSCTList.
func TestDeserializeSCTList(t *testing.T) {
// Here we make sure that empty SCT lists return an error
emptyLists := [][]byte{nil, {}}
for _, emptyList := range emptyLists {
_, err := DeserializeSCTList(emptyList)
if err == nil {
t.Fatalf("DeserializeSCTList(%v) should raise an error\n", emptyList)
}
}
// Here we make sure that an SCT list with a zero SCT is deserialized
// correctly
var zeroSCT ct.SignedCertificateTimestamp
serializedSCT, err := SerializeSCTList([]ct.SignedCertificateTimestamp{zeroSCT})
if err != nil {
t.Fatal(err)
}
deserializedSCTList, err := DeserializeSCTList(serializedSCT)
if err != nil {
t.Fatal(err)
}
if !sctEquals(zeroSCT, (deserializedSCTList)[0]) {
t.Fatal("SCTs don't match")
}
// Here we verify that an error is raised when the SCT list length
// field is greater than its actual length
serializedSCT, err = SerializeSCTList([]ct.SignedCertificateTimestamp{zeroSCT})
if err != nil {
t.Fatal(err)
}
serializedSCT[0] = 15
_, err = DeserializeSCTList(serializedSCT)
if err == nil {
t.Fatalf("DeserializeSCTList should raise an error when " +
"the SCT list length field and the list length don't match\n")
}
// Here we verify that an error is raised when the SCT list length
// field is less than its actual length
serializedSCT[0] = 0
serializedSCT[1] = 0
_, err = DeserializeSCTList(serializedSCT)
if err == nil {
t.Fatalf("DeserializeSCTList should raise an error when " +
"the SCT list length field and the list length don't match\n")
}
// Here we verify that an error is raised when the SCT length field is
// greater than its actual length
serializedSCT[0] = 0
serializedSCT[1] = 49
serializedSCT[2] = 1
_, err = DeserializeSCTList(serializedSCT)
if err == nil {
t.Fatalf("DeserializeSCTList should raise an error when " +
"the SCT length field and the SCT length don't match\n")
}
// Here we verify that an error is raised when the SCT length field is
// less than its actual length
serializedSCT[2] = 0
serializedSCT[3] = 0
_, err = DeserializeSCTList(serializedSCT)
if err == nil {
t.Fatalf("DeserializeSCTList should raise an error when " +
"the SCT length field and the SCT length don't match\n")
}
}
func TestSCTListFromOCSPResponse(t *testing.T) {
var response ocsp.Response
lst, err := SCTListFromOCSPResponse(&response)
if err != nil {
t.Fatal(err)
}
if len(lst) != 0 {
t.Fatal("SCTListFromOCSPResponse should return an empty SCT list for an empty extension")
}
var zeroSCT ct.SignedCertificateTimestamp
serializedSCTList, err := SerializeSCTList([]ct.SignedCertificateTimestamp{zeroSCT})
if err != nil {
t.Fatal("failed to serialize SCT list")
}
serializedSCTList, err = asn1.Marshal(serializedSCTList)
if err != nil {
t.Fatal("failed to serialize SCT list")
}
// The value of Id below is the object identifier of the OCSP Stapling
// SCT extension (see section 3.3. of RFC 6962).
response.Extensions = []pkix.Extension{{
Id: asn1.ObjectIdentifier{1, 3, 6, 1, 4, 1, 11129, 2, 4, 5},
Critical: false,
Value: serializedSCTList,
}}
lst, err = SCTListFromOCSPResponse(&response)
if err != nil {
t.Fatal(err)
}
if !sctEquals(zeroSCT, lst[0]) {
t.Fatal("SCTs don't match")
}
}