From f4d5af72975774b3878bfb330f7134f8dca6c521 Mon Sep 17 00:00:00 2001 From: Jacob Simpson Date: Tue, 14 Feb 2017 10:18:25 -0800 Subject: [PATCH] Split MakeCSR for new signature. --- staging/src/k8s.io/client-go/util/cert/csr.go | 52 ++++++++++++------- .../k8s.io/client-go/util/cert/csr_test.go | 31 ++++++++++- 2 files changed, 62 insertions(+), 21 deletions(-) diff --git a/staging/src/k8s.io/client-go/util/cert/csr.go b/staging/src/k8s.io/client-go/util/cert/csr.go index b20bb849bd0..280d249fea3 100644 --- a/staging/src/k8s.io/client-go/util/cert/csr.go +++ b/staging/src/k8s.io/client-go/util/cert/csr.go @@ -28,36 +28,48 @@ import ( // MakeCSR generates a PEM-encoded CSR using the supplied private key, subject, and SANs. // All key types that are implemented via crypto.Signer are supported (This includes *rsa.PrivateKey and *ecdsa.PrivateKey.) func MakeCSR(privateKey interface{}, subject *pkix.Name, dnsSANs []string, ipSANs []net.IP) (csr []byte, err error) { - // Customize the signature for RSA keys, depending on the key size - var sigType x509.SignatureAlgorithm - if privateKey, ok := privateKey.(*rsa.PrivateKey); ok { - keySize := privateKey.N.BitLen() - switch { - case keySize >= 4096: - sigType = x509.SHA512WithRSA - case keySize >= 3072: - sigType = x509.SHA384WithRSA - default: - sigType = x509.SHA256WithRSA - } - } - template := &x509.CertificateRequest{ - Subject: *subject, - SignatureAlgorithm: sigType, - DNSNames: dnsSANs, - IPAddresses: ipSANs, + Subject: *subject, + DNSNames: dnsSANs, + IPAddresses: ipSANs, } - csr, err = x509.CreateCertificateRequest(cryptorand.Reader, template, privateKey) + return MakeCSRFromTemplate(privateKey, template) +} + +// MakeCSRFromTemplate generates a PEM-encoded CSR using the supplied private +// key and certificate request as a template. All key types that are +// implemented via crypto.Signer are supported (This includes *rsa.PrivateKey +// and *ecdsa.PrivateKey.) +func MakeCSRFromTemplate(privateKey interface{}, template *x509.CertificateRequest) ([]byte, error) { + t := *template + t.SignatureAlgorithm = sigType(privateKey) + + csrDER, err := x509.CreateCertificateRequest(cryptorand.Reader, &t, privateKey) if err != nil { return nil, err } csrPemBlock := &pem.Block{ Type: "CERTIFICATE REQUEST", - Bytes: csr, + Bytes: csrDER, } return pem.EncodeToMemory(csrPemBlock), nil } + +func sigType(privateKey interface{}) x509.SignatureAlgorithm { + // Customize the signature for RSA keys, depending on the key size + if privateKey, ok := privateKey.(*rsa.PrivateKey); ok { + keySize := privateKey.N.BitLen() + switch { + case keySize >= 4096: + return x509.SHA512WithRSA + case keySize >= 3072: + return x509.SHA384WithRSA + default: + return x509.SHA256WithRSA + } + } + return x509.UnknownSignatureAlgorithm +} diff --git a/staging/src/k8s.io/client-go/util/cert/csr_test.go b/staging/src/k8s.io/client-go/util/cert/csr_test.go index 96973f7a92e..c2a0bbb3ec7 100644 --- a/staging/src/k8s.io/client-go/util/cert/csr_test.go +++ b/staging/src/k8s.io/client-go/util/cert/csr_test.go @@ -17,7 +17,9 @@ limitations under the License. package cert import ( + "crypto/x509" "crypto/x509/pkix" + "encoding/pem" "io/ioutil" "net" "testing" @@ -39,8 +41,35 @@ func TestMakeCSR(t *testing.T) { if err != nil { t.Fatal(err) } - _, err = MakeCSR(key, subject, dnsSANs, ipSANs) + csrPEM, err := MakeCSR(key, subject, dnsSANs, ipSANs) if err != nil { t.Error(err) } + csrBlock, rest := pem.Decode(csrPEM) + if csrBlock == nil { + t.Error("Unable to decode MakeCSR result.") + } + if len(rest) != 0 { + t.Error("Found more than one PEM encoded block in the result.") + } + if csrBlock.Type != "CERTIFICATE REQUEST" { + t.Errorf("Found block type %q, wanted 'CERTIFICATE REQUEST'", csrBlock.Type) + } + csr, err := x509.ParseCertificateRequest(csrBlock.Bytes) + if err != nil { + t.Errorf("Found %v parsing MakeCSR result as a CertificateRequest.", err) + } + if csr.Subject.CommonName != subject.CommonName { + t.Errorf("Wanted %v, got %v", subject, csr.Subject) + } + if len(csr.DNSNames) != 1 { + t.Errorf("Wanted 1 DNS name in the result, got %d", len(csr.DNSNames)) + } else if csr.DNSNames[0] != dnsSANs[0] { + t.Errorf("Wanted %v, got %v", dnsSANs[0], csr.DNSNames[0]) + } + if len(csr.IPAddresses) != 1 { + t.Errorf("Wanted 1 IP address in the result, got %d", len(csr.IPAddresses)) + } else if csr.IPAddresses[0].String() != ipSANs[0].String() { + t.Errorf("Wanted %v, got %v", ipSANs[0], csr.IPAddresses[0]) + } }