// Copyright 2014 ISRG. All rights reserved // This Source Code Form is subject to the terms of the Mozilla Public // License, v. 2.0. If a copy of the MPL was not distributed with this // file, You can obtain one at http://mozilla.org/MPL/2.0/. package ca import ( "bytes" "crypto/x509" "encoding/asn1" "encoding/hex" "fmt" "testing" "time" cfsslConfig "github.com/letsencrypt/boulder/Godeps/_workspace/src/github.com/cloudflare/cfssl/config" ocspConfig "github.com/letsencrypt/boulder/Godeps/_workspace/src/github.com/cloudflare/cfssl/ocsp/config" "github.com/letsencrypt/boulder/cmd" "github.com/letsencrypt/boulder/mocks" "github.com/letsencrypt/boulder/core" "github.com/letsencrypt/boulder/sa" "github.com/letsencrypt/boulder/test" ) var CAkeyPEM = "-----BEGIN RSA PRIVATE KEY-----\n" + "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\n" + "-----END RSA PRIVATE KEY-----" var CAcertPEM = "-----BEGIN CERTIFICATE-----\n" + "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\n" + "-----END CERTIFICATE-----" // CSR generated by Go: // * Random public key // * CN = not-example.com // * DNSNames = not-example.com, www.not-example.com var CNandSANCSRhex = "308202a130820189020100301a311830160603550403130f6e6f742d6578" + "616d706c652e636f6d30820122300d06092a864886f70d01010105000382" + "010f003082010a0282010100e56ccbe37003c150202e6f543f9eb1d0e590" + "76ac7f1f62654fa82fe131a23c66bd53a2f62ff7852015c84a394e36836d" + "2018eba278e0740c85c4c6102787400c2ef069b4a72e6eb8ad8d1da5d76b" + "f3e70dafc126578ed28cf40030e7fe5b5307ef630254726c639561b5445d" + "372847bdb02576aa3622a688158c6af09d3938dbeba4d670cec4325be73a" + "fa52a0a04dcba2f335f1e85020704db94ca125dce70b3209294c6c46ed4b" + "48b95d8d51ae2d2fd227116023a48ca7381e35fd302ad2999df625a4b5ee" + "82a0d0fefa88ac6a62b01674de75637ef83328202cda9930947d932000b0" + "e53b82e099ab60fec9c8b6d4eccdee508b6ebca7e6ca3f752046c8350203" + "010001a042304006092a864886f70d01090e31333031302f0603551d1104" + "283026820f6e6f742d6578616d706c652e636f6d82137777772e6e6f742d" + "6578616d706c652e636f6d300d06092a864886f70d01010b050003820101" + "008c4bf2ab4dfd28d768697eecc5be889a6275287c7dd24f9232ffad5675" + "de708c9cc911545d0e84f61b6584c5e237915bbf231d6518e7e228be2e65" + "b4d50bd9729ce9e6aee00482e014de4edd4b9a4f9a7777b8943ef3512dbf" + "940ac561c25b34ded9db1074136b978a65943ab1259608fb8109e008eac6" + "23d7b29b2f1fad3a8e358aa070ead688016d9efed6da43412b136903de07" + "137462d3f9203a344d84d7eb336999004e7e9972d5176001e2792f206e6c" + "7c70b86d312459f21751d29ea53b41f9d02a229f9d7615b2a7ac83e849d0" + "d0d9f8a08f8d7ba23295e77c95bc060c9227bfec0afb8c898e33c89903d7" + "bbde4cf059dcc3e6c4ae4eef207c499d62" // CSR generated by Go: // * Random public key // * CN = not-example.com // * DNSNames = [none] var NoSANCSRhex = "3082025f30820147020100301a311830160603550403130f6e6f742d6578" + "616d706c652e636f6d30820122300d06092a864886f70d01010105000382" + "010f003082010a0282010100aa6e56ff24906f93b855e7871dc8411a3cf7" + "678d9563627e8ca37ab17dfe814ef7f828d6aa92b717f0da9df56990b953" + "989d5afc3f2dddacd2b504b89782b49e55a04a64a4370d8ab1b2688f2596" + "98132e5ce536f812ef5eb13824a922bbb89e30d6f2cace77462b9e65264a" + "32320a7b348f9903b16640bc8c1c5f1208c6b456fd85bfa96ee9b7642c68" + "3ab05b142d249525a730b230b39f2ba8d6f253263b5c3948b1a3d8a3467f" + "7cfcdd1fdd6bff7828fda12784fd277be8c680fcdf2cc4676acff5df759f" + "f4bc712ee1a560157233cbf6bb4bcb91dd1c5d2824b42f4913e4715c1ba4" + "001fde0d90c274bfa81a79e4a0d00a7ddcbfdd8de4183b497487a20d0203" + "010001a000300d06092a864886f70d01010b050003820101000ead204cfd" + "45d307dd49de6937d7e2d8abf17490a49a8cee5250ef7799ef53229f8cfc" + "735b9f65d789f898945f3d5536a09932e241050bd5473c47a4ac2493707f" + "1142bf9a06d047384ad463463acb3744d435b4cff8c8b0f9673e8700e13b" + "6bc99a486823fa85f7707e1bb8430e62541715ab6cb3fae3efb8356042a5" + "c9f493dd08eff690570cce65cffc4fe354aa40957dc16a37a833aa968f62" + "693d5059d53f6a96a159195d3fb7b558d462de63d945d4e3680d2b1f2c98" + "33c3bfd92a9235de3d345a431ee5a675e0e18308bd2729413acd84432da4" + "2410e1b87ae70227dd9a98e49ee6aeea9eaff67f968691918201e94697f2" + "da010d6f939cea40c26038" // CSR generated by Go: // * Random public key // * C = US // * CN = [none] // * DNSNames = not-example.com var NoCNCSRhex = "3082027f30820167020100300d310b300906035504061302555330820122" + "300d06092a864886f70d01010105000382010f003082010a0282010100d8" + "b3c11610ce17614f6d78de3f079db430e479c38978da8cd625b7c70dd445" + "57fd99b9831693e6b9b09fb7c74a82058a1f1a4e1e087f04f93aa73bc35a" + "688440205a6f5fd56ff478c5554b14c3b2a1a0b5eed1aef7189ad848e117" + "04b1eb6c29b47ada40a5719a38ce2f2869896bf5405c2bafd4c7dfb99c0e" + "9f26f80145e16b73bbacf67aedcd3b7ce57bb5b67cf692aec7956d23c236" + "2336c2408b65469630dccca3ca006f28e36ca8c95dda84b6586f29c8de63" + "661c09b58253e386a74707394cbba4de165f2745a65b717b9fd4b8b84c09" + "85583b5c17d3e88bbf71c88eeeccb5d552d61cde7835ec83d6ec9b41114a" + "0583f8eeae8a536cb3ca5786c22ab30203010001a02d302b06092a864886" + "f70d01090e311e301c301a0603551d1104133011820f6e6f742d6578616d" + "706c652e636f6d300d06092a864886f70d01010b05000382010100430239" + "8db6b64b94d93399db32335232967ca6a748048483db8cb2b387871f758c" + "6f7bf1593624b142127847cd2a511897bbadd8ad038468fb309fa2161031" + "949b9ba24931b0d363ad2f8dae56a4c908ba748d41c664aa129dcb1a6f88" + "0b90502cd244d9abd8dd5e78f763730660655a350f1c25af95cf1f89dda9" + "076f4e6b84b6da9a98ed87f538624e4338fa0ff1a404e763dd6800694a21" + "d28595927606308aefa1ac7e8f5600b05e33c0a7b25d3a9f5032c7c25264" + "026c039733b179315254af4f25e90a1d00facd69313b36fdc66a5818fb49" + "a0d90e0745d66a82d337289c9968b3ec4a4826c530c758cacecc18e06366" + "dd8962c451c3ce22c2aed33726" // CSR generated by Go: // * Random public key // * C = US // * CN = [none] // * DNSNames = [none] var NoNameCSRhex = "308202523082013a020100300d310b300906035504061302555330820122" + "300d06092a864886f70d01010105000382010f003082010a0282010100bc" + "fae49f68f02c42500b2faf251628ee19e8ef048a35fef311c9c419c80606" + "ab37340ad6e25cf4cc63c0283994b4ba705d86950ad5298094e0b9684647" + "8d67abc695741317b4ff8da9fd33120342559cfdaf9109ac403f0d0bf9ff" + "54dd79fa2256b218a9bdb17c608167c7fcad4cf839733c7eab9589fe6137" + "e99bb24c24b7eb74e19f51ffee4ea62c4ab756f099ff5197c5032f60edff" + "36022b8a99d35aeb706854fa9a31ea8a362a2251f08b93023b32e1df771a" + "970f08a30ced656950b8ef71600d65d6995a0b92903b179c05a76f702a08" + "0b41402c308d8ab57f14b5516b89fe317e38e13d7adad7f7025743610881" + "9fb60268f0773b08b62ac8c8c84f2d0203010001a000300d06092a864886" + "f70d01010b050003820101001eda9ce8253e8b933348851acd38ab63cd64" + "f833d7ffc711f1b6e6a37a7deb7ad44b5589d90533ed61dfd48cab2775e2" + "a19c41f5cb69faa9dde856606822a3bf798381836214154c17bc037f23ad" + "67c84d876855c0aea871dc55bd14b2cd267e49b734bc7a38c29c334611bf" + "ec7efdc56a1512e25fd12ca99a5809b1b6a808caf6a8baefff7fb2bda454" + "5c226849674900ce7a1f90287ab31be80a4e2b6d64765b9d973628e60299" + "6423edd74e7a58005bd520d4173f0c30d935de530477480d7725d9758f9a" + "58c004d9e1e55af59ea517dfbd2bccca58216d8130b9f77c90328b2aa54b" + "1778a629b584f2bc059489a236131de9b444adca90218c31a499a485" // CSR generated by Go: // * Random public key // * CN = [none] // * DNSNames = a.example.com, a.example.com var DupeNameCSRhex = "308202943082017c020100300d310b300906035504061302555330820122" + "300d06092a864886f70d01010105000382010f003082010a0282010100ee" + "7d298c2a8237dd84e75e71dcfbbf8e1124327b103b01f3a99bc76b29be64" + "55329dc523ad1372ed12853dc74a775f2c79d1e4e28ae2a3ce69b78ec161" + "76b31056a72b5b87bcd7501ab9f15e83346e788c085e472718494849c012" + "ff6c25f12c040a0c68e99a46e8646523bf2b4103dcc7c4e583c6bf02c896" + "09b55e470beb15eaefc0bb6d57aca39e75312833e87faf2ba33e12a3204c" + "a19e5a1016c85b750619be9cb76fb93e653f3169b873dce42deab328a034" + "57454fd8e135e125bdb4529144a34bcc5ab20f25c6b33300ab2ad994d251" + "9261920da78e05b1c8847852e93a74000e7b29304ef2cccfa5315888150c" + "14e9d51e2c343de44e6bd2903740ef0203010001a042304006092a864886" + "f70d01090e31333031302f0603551d11042830268211612e6e6f742d6578" + "616d706c652e636f6d8211612e6e6f742d6578616d706c652e636f6d300d" + "06092a864886f70d01010b050003820101001358a156338bacd21bd66f35" + "83bf26afbaa6750f1d5d8e6285d062d5ae4f379000cd53568e8ef11bb542" + "97d906879614960266fece8f9060881c3b0ec34a1bb4b28f62cc444e5831" + "09c278d21265b2ef6f120ae8bc2554ba46b60e8d46a8cd3093ea6b72cb42" + "9d2d6072273e4a0c1a5ec3316cc2495a2776698f12cd4f4226f4b3e85f87" + "0b0f32785cf823b9dfa7116eec8a6f9bdc5cf01c1fff46afbb55e636ced4" + "0ccdf4cab09e7717aa2a67c5573590bb5d461cb13cc57b8451314ed3613e" + "21757aeb846f5b33f107a01f93a718b3a83539562e6486a72f114df898ed" + "c34e38d9bbdb96d0b8ab243c46da274cece70deb771985c477098468063a" + "8400ecb6" // CSR generated by Go: // * Random pulic key // * CN = [none] // * DNSNames = not-example.com, www.not-example.com, mail.example.com var TooManyNameCSRhex = "308202aa30820192020100300d310b300906035504061302555330820122" + "300d06092a864886f70d01010105000382010f003082010a0282010100a7" + "75d8f833651d9a4cfa1fa0e134912b772366c7d070ca3183d3c79ffc99bb" + "c706d328c2389b360b99f60e9a447023a019931d410b4cea0eafb7869a6d" + "879d6a976163e3e8de715bcc6a0d80654484450a837b9abae0c5c2fa28dd" + "4f33d8043c32e2ecb9c41a0b6c7df60f9f6eaaef6cef38722db9b278b773" + "c8251c75d63c36c5708024d3ec67372c205342ad93a68cc4cc9f90a92789" + "b4fcdcbe050990b6e3edf2655c9df8365eb8be89a6ee4f80267e056e5cca" + "853094a96ec1d76a00cef8724ed3b402f602c30cfc16128abc25bab65a9c" + "f8a046b576e314a5d01e0887cfde86c01094b621e2230fc5db588ffd0e0e" + "2454e60e8b83a9e82f33419abc62710203010001a058305606092a864886" + "f70d01090e3149304730450603551d11043e303c820f6e6f742d6578616d" + "706c652e636f6d82137777772e6e6f742d6578616d706c652e636f6d8214" + "6d61696c2e6e6f742d6578616d706c652e636f6d300d06092a864886f70d" + "01010b05000382010100486c9cea322a3a81ec9b828ccb303524cc914e0b" + "81b45ea23214b0dd254a79cdc77d1a661c7de8dcfcc7d404c0ad8707a67a" + "1ecc43ed5b4a7d96fabe41cab5ad8fde18f894bd2e57c8291b3bb0220c95" + "7c178c1c4251be4252663a14e4c303a8563bb86056f8e07ab14082693f72" + "3a55efe017b15d22cd31b6aa7b1bb5e1078e6f7b7fb12962230b192e0d40" + "a4f4515d6f2922b587e3586ea7f61ae7196cfeab5b4e5f78e03de0dab5a6" + "a537e6740bbb2a72b32c94068b4b46766f94ab3d24a704869d127fab6fb9" + "9c470101aed4852cd7b3a0a5a489b264779118b30d51907dc745879a821b" + "85f19a24d20dc5b48141eff276aa73bb41141305905b0223ded7" // CSR generated by Go: // * Random public key -- 512 bits long // * CN = (none) // * DNSNames = not-example.com, www.not-example.com, mail.not-example.com var ShortKeyCSRhex = "3082011f3081ca020100300d310b30090603550406130255" + "53305c300d06092a864886f70d0101010500034b00304802" + "4100ca8ff48b32197226bbe6398b6ba62dd4f09be06dc742" + "4b0c6321323d90c58e93cad2b3c91b5809493836f110dfc6" + "bbb3eca5575e6416a3a8189e782f41a29b990203010001a0" + "58305606092a864886f70d01090e3149304730450603551d" + "11043e303c820f6e6f742d6578616d706c652e636f6d8213" + "7777772e6e6f742d6578616d706c652e636f6d82146d6169" + "6c2e6e6f742d6578616d706c652e636f6d300d06092a8648" + "86f70d0101050500034100bfdc34a0a728918f4221413631" + "a70656db80ddb1b8126a02e6ca92c48301c350f29b6049b3" + "c4d70bf22ac273c951e60dd22f6f427b8d234e85f6881fba" + "35c288" // CSR generated by Go: // * Random public key // * CN = (none) // * DNSNames = not-example.com, www.not-example.com, mail.not-example.com // * Signature algorithm: SHA1WithRSA var BadAlgorithmCSRhex = "308202aa30820192020100300d310b300906035504061302" + "555330820122300d06092a864886f70d0101010500038201" + "0f003082010a02820101009f70f8d60b07f24b6960e18da8" + "aabdc993c583a6c43c81ae256a1d4328146f3e907fb65dc4" + "f30cb27c96d020e55bf116ef33f3696d2d957b9b408d6762" + "2fe562311c96023100985ed8bc10929e7c552d7674027b63" + "3973ede006b1ba338f9f4b7a88b4ea768c70632dde0f202a" + "f59d41bf9aaa841e022735cfb2822a919b2b9ada07bdd569" + "347894f1aa4908ee86d2019eb8980e819af20b5084eb11f7" + "2f4f51e77c99d09e556ae84a720fa728962c5f7db176ce0a" + "27b824fc63849ad5493ba790cd8f0c0aedf22d7979a95fce" + "f4dfa552f8f85e15f5e7e427002b56f03f040e7cd43145d7" + "7732ef9c4568b0f22aa91ca1e5a133f862939ed14c1859a1" + "fdd36f0203010001a058305606092a864886f70d01090e31" + "49304730450603551d11043e303c820f6e6f742d6578616d" + "706c652e636f6d82137777772e6e6f742d6578616d706c65" + "2e636f6d82146d61696c2e6e6f742d6578616d706c652e63" + "6f6d300d06092a864886f70d0101050500038201010056cf" + "65a690ef9d279caa0b5e44c51a1f97631c43e9f0c67fd329" + "6b0d33acf06a695130fbdb8842a40d690549ab05f44b1738" + "e8419b395563426d76cc5611d17ade13c96c92496a2ed008" + "a78687f25c892af274afd9518540300edd160dc47887b402" + "a0705b156e9b623f47a3bdaea93b84a4cf873ac1e9861b67" + "f742024eff40c7c8e33243a953e9874e678c3f4cd24b4699" + "28214425ef7b9181d8b10b7f07f557bef7c4b22689be4b2a" + "42a0b6f0aaefa4dc8913338785e7f8fc2b1b95c4d189d10f" + "72dbe575cdd6985e2d6eb0d0cbe962de0986cbcc8ca30dc8" + "fa254808b0ee8946253830c087da95404181cb88ec59d399" + "b4b3fcc21bbb1c9f3e1b29fd576a" // Times for validity checking var FarFuture = time.Date(2100, 1, 1, 0, 0, 0, 0, time.UTC) var FarPast = time.Date(1950, 1, 1, 0, 0, 0, 0, time.UTC) var log = mocks.UseMockLog() // CFSSL config const profileName = "ee" const caKeyFile = "../test/test-ca.key" const caCertFile = "../test/test-ca.pem" const issuerCert = "../test/test-ca.pem" // TODO(jmhodges): change this to boulder_ca_test database var dbConnStr = "mysql+tcp://boulder@localhost:3306/boulder_test" var exPA = cmd.PAConfig{ DBConnect: dbConnStr, } func setup(t *testing.T) (core.CertificateAuthorityDatabase, core.StorageAuthority, cmd.CAConfig, func()) { // Create an SA dbMap, err := sa.NewDbMap(dbConnStr) if err != nil { t.Fatalf("Failed to create dbMap: %s", err) } ssa, err := sa.NewSQLStorageAuthority(dbMap) if err != nil { t.Fatalf("Failed to create SA: %s", err) } if err = ssa.CreateTablesIfNotExists(); err != nil { t.Fatalf("Failed to create tables: %s", err) } if err = dbMap.TruncateTables(); err != nil { t.Fatalf("Failed to truncate tables: %s", err) } cadb, caDBCleanUp := caDBImpl(t) cleanUp := func() { if err = dbMap.TruncateTables(); err != nil { t.Fatalf("Failed to truncate tables after the test: %s", err) } dbMap.Db.Close() caDBCleanUp() } // Create a CA caConfig := cmd.CAConfig{ Profile: profileName, SerialPrefix: 17, Key: cmd.KeyConfig{ File: caKeyFile, }, TestMode: true, Expiry: "8760h", LifespanOCSP: "45m", MaxNames: 2, CFSSL: cfsslConfig.Config{ Signing: &cfsslConfig.Signing{ Profiles: map[string]*cfsslConfig.SigningProfile{ profileName: &cfsslConfig.SigningProfile{ Usage: []string{"server auth"}, CA: false, IssuerURL: []string{"http://not-example.com/issuer-url"}, OCSP: "http://not-example.com/ocsp", CRL: "http://not-example.com/crl", Policies: []cfsslConfig.CertificatePolicy{ cfsslConfig.CertificatePolicy{ ID: cfsslConfig.OID(asn1.ObjectIdentifier{2, 23, 140, 1, 2, 1}), }, }, ExpiryString: "8760h", Backdate: time.Hour, CSRWhitelist: &cfsslConfig.CSRWhitelist{ PublicKeyAlgorithm: true, PublicKey: true, SignatureAlgorithm: true, }, }, }, Default: &cfsslConfig.SigningProfile{ ExpiryString: "8760h", }, }, OCSP: &ocspConfig.Config{ CACertFile: issuerCert, ResponderCertFile: issuerCert, KeyFile: caKeyFile, }, }, } return cadb, ssa, caConfig, cleanUp } func TestFailNoSerial(t *testing.T) { cadb, _, caConfig, cleanUp := setup(t) defer cleanUp() caConfig.SerialPrefix = 0 _, err := NewCertificateAuthorityImpl(cadb, caConfig, issuerCert, exPA) test.AssertError(t, err, "CA should have failed with no SerialPrefix") } func TestRevoke(t *testing.T) { cadb, storageAuthority, caConfig, cleanUp := setup(t) defer cleanUp() ca, err := NewCertificateAuthorityImpl(cadb, caConfig, caCertFile, exPA) test.AssertNotError(t, err, "Failed to create CA") if err != nil { return } ca.SA = storageAuthority ca.MaxKeySize = 4096 csrDER, _ := hex.DecodeString(CNandSANCSRhex) csr, _ := x509.ParseCertificateRequest(csrDER) certObj, err := ca.IssueCertificate(*csr, 1, FarFuture) test.AssertNotError(t, err, "Failed to sign certificate") if err != nil { return } cert, err := x509.ParseCertificate(certObj.DER) test.AssertNotError(t, err, "Certificate failed to parse") serialString := core.SerialToString(cert.SerialNumber) err = ca.RevokeCertificate(serialString, 0) test.AssertNotError(t, err, "Revocation failed") status, err := storageAuthority.GetCertificateStatus(serialString) test.AssertNotError(t, err, "Failed to get cert status") test.AssertEquals(t, status.Status, core.OCSPStatusRevoked) secondAgo := time.Now().Add(-time.Second) test.Assert(t, status.OCSPLastUpdated.After(secondAgo), fmt.Sprintf("OCSP LastUpdated was more than a second old: %v", status.OCSPLastUpdated)) } func TestIssueCertificate(t *testing.T) { cadb, storageAuthority, caConfig, cleanUp := setup(t) defer cleanUp() ca, err := NewCertificateAuthorityImpl(cadb, caConfig, caCertFile, exPA) test.AssertNotError(t, err, "Failed to create CA") ca.SA = storageAuthority ca.MaxKeySize = 4096 /* // Uncomment to test with a local signer signer, _ := local.NewSigner(caKey, caCert, x509.SHA256WithRSA, nil) ca := CertificateAuthorityImpl{ Signer: signer, SA: sa, } */ csrs := []string{CNandSANCSRhex, NoSANCSRhex, NoCNCSRhex} for _, csrHEX := range csrs { csrDER, _ := hex.DecodeString(csrHEX) csr, _ := x509.ParseCertificateRequest(csrDER) // Sign CSR issuedCert, err := ca.IssueCertificate(*csr, 1, FarFuture) test.AssertNotError(t, err, "Failed to sign certificate") if err != nil { continue } // Verify cert contents cert, err := x509.ParseCertificate(issuedCert.DER) test.AssertNotError(t, err, "Certificate failed to parse") test.AssertEquals(t, cert.Subject.CommonName, "not-example.com") switch len(cert.DNSNames) { case 1: if cert.DNSNames[0] != "not-example.com" { t.Errorf("Improper list of domain names %v", cert.DNSNames) } case 2: switch { case (cert.DNSNames[0] == "not-example.com" && cert.DNSNames[1] == "www.not-example.com"): t.Log("case 1") case (cert.DNSNames[0] == "www.not-example.com" && cert.DNSNames[1] == "not-example.com"): t.Log("case 2") default: t.Errorf("Improper list of domain names %v", cert.DNSNames) } default: t.Errorf("Improper list of domain names %v", cert.DNSNames) } // Test is broken by CFSSL Issue #156 // https://github.com/cloudflare/cfssl/issues/156 if len(cert.Subject.Country) > 0 { // Uncomment the Errorf as soon as upstream #156 is fixed // t.Errorf("Subject contained unauthorized values: %v", cert.Subject) t.Logf("Subject contained unauthorized values: %v", cert.Subject) } // Verify that the cert got stored in the DB serialString := core.SerialToString(cert.SerialNumber) storedCert, err := storageAuthority.GetCertificate(serialString) test.AssertNotError(t, err, fmt.Sprintf("Certificate %s not found in database", serialString)) test.Assert(t, bytes.Equal(issuedCert.DER, storedCert.DER), "Retrieved cert not equal to issued cert.") certStatus, err := storageAuthority.GetCertificateStatus(serialString) test.AssertNotError(t, err, fmt.Sprintf("Error fetching status for certificate %s", serialString)) test.Assert(t, certStatus.Status == core.OCSPStatusGood, "Certificate status was not good") test.Assert(t, certStatus.SubscriberApproved == false, "Subscriber shouldn't have approved cert yet.") } } func TestRejectNoName(t *testing.T) { cadb, storageAuthority, caConfig, cleanUp := setup(t) defer cleanUp() ca, err := NewCertificateAuthorityImpl(cadb, caConfig, caCertFile, exPA) test.AssertNotError(t, err, "Failed to create CA") ca.SA = storageAuthority ca.MaxKeySize = 4096 // Test that the CA rejects CSRs with no names csrDER, _ := hex.DecodeString(NoNameCSRhex) csr, _ := x509.ParseCertificateRequest(csrDER) _, err = ca.IssueCertificate(*csr, 1, FarFuture) if err == nil { t.Errorf("CA improperly agreed to create a certificate with no name") } } func TestRejectTooManyNames(t *testing.T) { cadb, storageAuthority, caConfig, cleanUp := setup(t) defer cleanUp() ca, err := NewCertificateAuthorityImpl(cadb, caConfig, caCertFile, exPA) test.AssertNotError(t, err, "Failed to create CA") ca.SA = storageAuthority // Test that the CA rejects a CSR with too many names csrDER, _ := hex.DecodeString(TooManyNameCSRhex) csr, _ := x509.ParseCertificateRequest(csrDER) _, err = ca.IssueCertificate(*csr, 1, FarFuture) test.Assert(t, err != nil, "Issued certificate with too many names") } func TestDeduplication(t *testing.T) { cadb, storageAuthority, caConfig, cleanUp := setup(t) defer cleanUp() ca, err := NewCertificateAuthorityImpl(cadb, caConfig, caCertFile, exPA) test.AssertNotError(t, err, "Failed to create CA") ca.SA = storageAuthority ca.MaxKeySize = 4096 // Test that the CA collapses duplicate names csrDER, _ := hex.DecodeString(DupeNameCSRhex) csr, _ := x509.ParseCertificateRequest(csrDER) cert, err := ca.IssueCertificate(*csr, 1, FarFuture) test.AssertNotError(t, err, "Failed to gracefully handle a CSR with duplicate names") if err != nil { return } parsedCert, err := x509.ParseCertificate(cert.DER) test.AssertNotError(t, err, "Error parsing certificate produced by CA") if err != nil { return } correctName := "a.not-example.com" correctNames := len(parsedCert.DNSNames) == 1 && parsedCert.DNSNames[0] == correctName && parsedCert.Subject.CommonName == correctName test.Assert(t, correctNames, "Incorrect set of names in deduplicated certificate") } func TestRejectValidityTooLong(t *testing.T) { cadb, storageAuthority, caConfig, cleanUp := setup(t) defer cleanUp() ca, err := NewCertificateAuthorityImpl(cadb, caConfig, caCertFile, exPA) test.AssertNotError(t, err, "Failed to create CA") ca.SA = storageAuthority ca.MaxKeySize = 4096 // Test that the CA rejects CSRs that would expire after the intermediate cert csrDER, _ := hex.DecodeString(NoCNCSRhex) csr, _ := x509.ParseCertificateRequest(csrDER) _, err = ca.IssueCertificate(*csr, 1, FarPast) test.Assert(t, err == nil, "Can issue a certificate that expires after the underlying authorization.") // Test that the CA rejects CSRs that would expire after the intermediate cert csrDER, _ = hex.DecodeString(NoCNCSRhex) csr, _ = x509.ParseCertificateRequest(csrDER) ca.NotAfter = time.Now() _, err = ca.IssueCertificate(*csr, 1, FarFuture) test.AssertEquals(t, err.Error(), "Cannot issue a certificate that expires after the intermediate certificate.") } func TestShortKey(t *testing.T) { cadb, storageAuthority, caConfig, cleanUp := setup(t) defer cleanUp() ca, err := NewCertificateAuthorityImpl(cadb, caConfig, caCertFile, exPA) ca.SA = storageAuthority ca.MaxKeySize = 4096 // Test that the CA rejects CSRs that would expire after the intermediate cert csrDER, _ := hex.DecodeString(ShortKeyCSRhex) csr, _ := x509.ParseCertificateRequest(csrDER) _, err = ca.IssueCertificate(*csr, 1, FarFuture) test.Assert(t, err != nil, "Issued a certificate with too short a key.") } func TestRejectBadAlgorithm(t *testing.T) { cadb, storageAuthority, caConfig, cleanUp := setup(t) defer cleanUp() ca, err := NewCertificateAuthorityImpl(cadb, caConfig, caCertFile, exPA) ca.SA = storageAuthority ca.MaxKeySize = 4096 // Test that the CA rejects CSRs that would expire after the intermediate cert csrDER, _ := hex.DecodeString(BadAlgorithmCSRhex) csr, _ := x509.ParseCertificateRequest(csrDER) _, err = ca.IssueCertificate(*csr, 1, FarFuture) test.Assert(t, err != nil, "Issued a certificate based on a CSR with a weak algorithm.") }