From 57782ac3c12a4c837edac0e3874dc33dd671565c Mon Sep 17 00:00:00 2001 From: Ludovic Fernandez Date: Mon, 18 Jun 2018 15:44:18 +0200 Subject: [PATCH] tls-alpn: add a function to return PEM blocks. (#579) * feature(tls-alpn): add function to return PEM blocks. --- acme/tls_alpn_challenge.go | 55 ++++++++++++++++++------------- acme/tls_alpn_challenge_server.go | 6 ++-- 2 files changed, 35 insertions(+), 26 deletions(-) diff --git a/acme/tls_alpn_challenge.go b/acme/tls_alpn_challenge.go index 6b346cd0..397d0709 100644 --- a/acme/tls_alpn_challenge.go +++ b/acme/tls_alpn_challenge.go @@ -11,9 +11,8 @@ import ( "github.com/xenolf/lego/log" ) -// idPeAcmeIdentifierV1 is the SMI Security for PKIX Certification Extension -// OID referencing the ACME extension. Reference: -// https://tools.ietf.org/html/draft-ietf-acme-tls-alpn-01#section-5.1 +// idPeAcmeIdentifierV1 is the SMI Security for PKIX Certification Extension OID referencing the ACME extension. +// Reference: https://tools.ietf.org/html/draft-ietf-acme-tls-alpn-01#section-5.1 var idPeAcmeIdentifierV1 = asn1.ObjectIdentifier{1, 3, 6, 1, 5, 5, 7, 1, 30, 1} type tlsALPNChallenge struct { @@ -46,31 +45,20 @@ func (t *tlsALPNChallenge) Solve(chlng challenge, domain string) error { return t.validate(t.jws, domain, chlng.URL, challenge{Type: chlng.Type, Token: chlng.Token, KeyAuthorization: keyAuth}) } -// TLSALPNChallengeCert returns a certificate with the acmeValidation-v1 -// extension and domain name for the `tls-alpn-01` challenge. -func TLSALPNChallengeCert(domain, keyAuth string) (*tls.Certificate, error) { - // Generate a new RSA key for the certificates. - tempPrivKey, err := generatePrivateKey(RSA2048) - if err != nil { - return nil, err - } - - // Encode the private key into a PEM format. We'll need to use it to - // generate the x509 keypair. - rsaPrivKey := tempPrivKey.(*rsa.PrivateKey) - rsaPrivPEM := pemEncode(rsaPrivKey) - +// TLSALPNChallengeBlocks returns PEM blocks (certPEMBlock, keyPEMBlock) with the acmeValidation-v1 extension +// and domain name for the `tls-alpn-01` challenge. +func TLSALPNChallengeBlocks(domain, keyAuth string) ([]byte, []byte, error) { // Compute the SHA-256 digest of the key authorization. zBytes := sha256.Sum256([]byte(keyAuth)) value, err := asn1.Marshal(zBytes[:sha256.Size]) if err != nil { - return nil, err + return nil, nil, err } - // Add the keyAuth digest as the acmeValidation-v1 extension (marked as - // critical such that it won't be used by non-ACME software). Reference: - // https://tools.ietf.org/html/draft-ietf-acme-tls-alpn-01#section-3 + // Add the keyAuth digest as the acmeValidation-v1 extension + // (marked as critical such that it won't be used by non-ACME software). + // Reference: https://tools.ietf.org/html/draft-ietf-acme-tls-alpn-01#section-3 extensions := []pkix.Extension{ { Id: idPeAcmeIdentifierV1, @@ -79,9 +67,30 @@ func TLSALPNChallengeCert(domain, keyAuth string) (*tls.Certificate, error) { }, } - // Generate the PEM certificate using the provided private key, domain, and - // extra extensions. + // Generate a new RSA key for the certificates. + tempPrivKey, err := generatePrivateKey(RSA2048) + if err != nil { + return nil, nil, err + } + + rsaPrivKey := tempPrivKey.(*rsa.PrivateKey) + + // Generate the PEM certificate using the provided private key, domain, and extra extensions. tempCertPEM, err := generatePemCert(rsaPrivKey, domain, extensions) + if err != nil { + return nil, nil, err + } + + // Encode the private key into a PEM format. We'll need to use it to generate the x509 keypair. + rsaPrivPEM := pemEncode(rsaPrivKey) + + return tempCertPEM, rsaPrivPEM, nil +} + +// TLSALPNChallengeCert returns a certificate with the acmeValidation-v1 extension +// and domain name for the `tls-alpn-01` challenge. +func TLSALPNChallengeCert(domain, keyAuth string) (*tls.Certificate, error) { + tempCertPEM, rsaPrivPEM, err := TLSALPNChallengeBlocks(domain, keyAuth) if err != nil { return nil, err } diff --git a/acme/tls_alpn_challenge_server.go b/acme/tls_alpn_challenge_server.go index 73f605a5..8d33668e 100644 --- a/acme/tls_alpn_challenge_server.go +++ b/acme/tls_alpn_challenge_server.go @@ -8,8 +8,8 @@ import ( ) const ( - // acmeTLS1Protocol is the ALPN Protocol ID for the ACME-TLS/1 Protocol. - acmeTLS1Protocol = "acme-tls/1" + // ACMETLS1Protocol is the ALPN Protocol ID for the ACME-TLS/1 Protocol. + ACMETLS1Protocol = "acme-tls/1" // defaultTLSPort is the port that the TLSALPNProviderServer will default to // when no other port is provided. @@ -55,7 +55,7 @@ func (t *TLSALPNProviderServer) Present(domain, token, keyAuth string) error { // We must set that the `acme-tls/1` application level protocol is supported // so that the protocol negotiation can succeed. Reference: // https://tools.ietf.org/html/draft-ietf-acme-tls-alpn-01#section-5.2 - tlsConf.NextProtos = []string{acmeTLS1Protocol} + tlsConf.NextProtos = []string{ACMETLS1Protocol} // Create the listener with the created tls.Config. t.listener, err = tls.Listen("tcp", net.JoinHostPort(t.iface, t.port), tlsConf)