This commit is contained in:
Richard Barnes 2015-05-30 17:32:09 -04:00
parent 9b747d08be
commit 4ec0e9fd67
4 changed files with 57 additions and 2 deletions

View File

@ -45,6 +45,8 @@ type Config struct {
// How long issue certificates are valid for, should match expiry field
// in cfssl config.
Expiry string
// The maximum number of subjectAltNames in a single certificate
MaxNames int
}
// CertificateAuthorityImpl represents a CA that signs certificates, CRLs, and
@ -60,6 +62,7 @@ type CertificateAuthorityImpl struct {
Prefix int // Prepended to the serial number
ValidityPeriod time.Duration
NotAfter time.Time
MaxNames int
}
// NewCertificateAuthorityImpl creates a CA that talks to a remote CFSSL
@ -139,6 +142,8 @@ func NewCertificateAuthorityImpl(cadb core.CertificateAuthorityDatabase, config
return nil, err
}
ca.MaxNames = config.MaxNames
return ca, nil
}
@ -256,6 +261,11 @@ func (ca *CertificateAuthorityImpl) IssueCertificate(csr x509.CertificateRequest
// Collapse any duplicate names. Note that this operation may re-order the names
hostNames = uniqueNames(hostNames)
if ca.MaxNames > 0 && len(hostNames) > ca.MaxNames {
err = errors.New(fmt.Sprintf("Certificate request has %d > %d names", len(hostNames), ca.MaxNames))
ca.log.WarningErr(err)
return emptyCert, err
}
if ca.NotAfter.Before(time.Now().Add(ca.ValidityPeriod)) {
err = errors.New("Cannot issue a certificate that expires after the intermediate certificate.")

View File

@ -251,6 +251,34 @@ var DUPE_NAME_CSR_HEX = "308202943082017c020100300d310b3009060355040613025553308
"c34e38d9bbdb96d0b8ab243c46da274cece70deb771985c477098468063a" +
"8400ecb6"
// CSR generated by Go:
// * Random pulic key
// * CN = [none]
// * DNSNames = not-example.com, www.not-example.com, mail.example.com
var TOO_MANY_NAME_CSR_HEX = "308202aa30820192020100300d310b300906035504061302555330820122" +
"300d06092a864886f70d01010105000382010f003082010a0282010100a7" +
"75d8f833651d9a4cfa1fa0e134912b772366c7d070ca3183d3c79ffc99bb" +
"c706d328c2389b360b99f60e9a447023a019931d410b4cea0eafb7869a6d" +
"879d6a976163e3e8de715bcc6a0d80654484450a837b9abae0c5c2fa28dd" +
"4f33d8043c32e2ecb9c41a0b6c7df60f9f6eaaef6cef38722db9b278b773" +
"c8251c75d63c36c5708024d3ec67372c205342ad93a68cc4cc9f90a92789" +
"b4fcdcbe050990b6e3edf2655c9df8365eb8be89a6ee4f80267e056e5cca" +
"853094a96ec1d76a00cef8724ed3b402f602c30cfc16128abc25bab65a9c" +
"f8a046b576e314a5d01e0887cfde86c01094b621e2230fc5db588ffd0e0e" +
"2454e60e8b83a9e82f33419abc62710203010001a058305606092a864886" +
"f70d01090e3149304730450603551d11043e303c820f6e6f742d6578616d" +
"706c652e636f6d82137777772e6e6f742d6578616d706c652e636f6d8214" +
"6d61696c2e6e6f742d6578616d706c652e636f6d300d06092a864886f70d" +
"01010b05000382010100486c9cea322a3a81ec9b828ccb303524cc914e0b" +
"81b45ea23214b0dd254a79cdc77d1a661c7de8dcfcc7d404c0ad8707a67a" +
"1ecc43ed5b4a7d96fabe41cab5ad8fde18f894bd2e57c8291b3bb0220c95" +
"7c178c1c4251be4252663a14e4c303a8563bb86056f8e07ab14082693f72" +
"3a55efe017b15d22cd31b6aa7b1bb5e1078e6f7b7fb12962230b192e0d40" +
"a4f4515d6f2922b587e3586ea7f61ae7196cfeab5b4e5f78e03de0dab5a6" +
"a537e6740bbb2a72b32c94068b4b46766f94ab3d24a704869d127fab6fb9" +
"9c470101aed4852cd7b3a0a5a489b264779118b30d51907dc745879a821b" +
"85f19a24d20dc5b48141eff276aa73bb41141305905b0223ded7"
// CFSSL config
const hostPort = "localhost:9000"
const authKey = "79999d86250c367a2b517a1ae7d409c1"
@ -355,6 +383,7 @@ func setup(t *testing.T) (cadb core.CertificateAuthorityDatabase, storageAuthori
IssuerKey: "../test/test-ca.key",
TestMode: true,
Expiry: "8760h",
MaxNames: 2,
}
return cadb, storageAuthority, caConfig
}
@ -369,6 +398,7 @@ func TestFailNoSerial(t *testing.T) {
func TestRevoke(t *testing.T) {
cadb, storageAuthority, caConfig := setup(t)
ca, err := NewCertificateAuthorityImpl(cadb, caConfig)
test.AssertNotError(t, err, "Failed to create CA")
ca.SA = storageAuthority
csrDER, _ := hex.DecodeString(CN_AND_SAN_CSR_HEX)
@ -482,6 +512,19 @@ func TestRejectNoName(t *testing.T) {
}
}
func TestRejectTooManyNames(t *testing.T) {
cadb, storageAuthority, caConfig := setup(t)
ca, err := NewCertificateAuthorityImpl(cadb, caConfig)
test.AssertNotError(t, err, "Failed to create CA")
ca.SA = storageAuthority
// Test that the CA collapses duplicate names
csrDER, _ := hex.DecodeString(TOO_MANY_NAME_CSR_HEX)
csr, _ := x509.ParseCertificateRequest(csrDER)
_, err = ca.IssueCertificate(*csr, 1)
test.Assert(t, err != nil, "Issued certificate with too many names")
}
func TestDeduplication(t *testing.T) {
cadb, storageAuthority, caConfig := setup(t)
ca, err := NewCertificateAuthorityImpl(cadb, caConfig)

View File

@ -46,7 +46,8 @@
"issuerCert": "test/test-ca.pem",
"_comment": "This should only be present in testMode. In prod use an HSM.",
"issuerKey": "test/test-ca.key",
"expiry": "8760h"
"expiry": "8760h",
"maxNames": 1000
},
"sa": {

View File

@ -46,7 +46,8 @@
"issuerCert": "test/test-ca.pem",
"_comment": "This should only be present in testMode. In prod use an HSM.",
"issuerKey": "test/test-ca.key",
"expiry": "8760h"
"expiry": "8760h",
"maxNames": 1000
},
"sa": {