tls-alpn: add a function to return PEM blocks. (#579)

* feature(tls-alpn): add function to return PEM blocks.
This commit is contained in:
Ludovic Fernandez 2018-06-18 15:44:18 +02:00 committed by GitHub
parent d457f70ae0
commit 57782ac3c1
No known key found for this signature in database
GPG key ID: 4AEE18F83AFDEB23
2 changed files with 35 additions and 26 deletions

View file

@ -11,9 +11,8 @@ import (
"github.com/xenolf/lego/log" "github.com/xenolf/lego/log"
) )
// idPeAcmeIdentifierV1 is the SMI Security for PKIX Certification Extension // idPeAcmeIdentifierV1 is the SMI Security for PKIX Certification Extension OID referencing the ACME extension.
// OID referencing the ACME extension. Reference: // Reference: https://tools.ietf.org/html/draft-ietf-acme-tls-alpn-01#section-5.1
// 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} var idPeAcmeIdentifierV1 = asn1.ObjectIdentifier{1, 3, 6, 1, 5, 5, 7, 1, 30, 1}
type tlsALPNChallenge struct { 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}) 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 // TLSALPNChallengeBlocks returns PEM blocks (certPEMBlock, keyPEMBlock) with the acmeValidation-v1 extension
// extension and domain name for the `tls-alpn-01` challenge. // and domain name for the `tls-alpn-01` challenge.
func TLSALPNChallengeCert(domain, keyAuth string) (*tls.Certificate, error) { func TLSALPNChallengeBlocks(domain, keyAuth string) ([]byte, []byte, 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)
// Compute the SHA-256 digest of the key authorization. // Compute the SHA-256 digest of the key authorization.
zBytes := sha256.Sum256([]byte(keyAuth)) zBytes := sha256.Sum256([]byte(keyAuth))
value, err := asn1.Marshal(zBytes[:sha256.Size]) value, err := asn1.Marshal(zBytes[:sha256.Size])
if err != nil { if err != nil {
return nil, err return nil, nil, err
} }
// Add the keyAuth digest as the acmeValidation-v1 extension (marked as // Add the keyAuth digest as the acmeValidation-v1 extension
// critical such that it won't be used by non-ACME software). Reference: // (marked as critical such that it won't be used by non-ACME software).
// https://tools.ietf.org/html/draft-ietf-acme-tls-alpn-01#section-3 // Reference: https://tools.ietf.org/html/draft-ietf-acme-tls-alpn-01#section-3
extensions := []pkix.Extension{ extensions := []pkix.Extension{
{ {
Id: idPeAcmeIdentifierV1, 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 // Generate a new RSA key for the certificates.
// extra extensions. 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) 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 { if err != nil {
return nil, err return nil, err
} }

View file

@ -8,8 +8,8 @@ import (
) )
const ( const (
// acmeTLS1Protocol is the ALPN Protocol ID for the ACME-TLS/1 Protocol. // ACMETLS1Protocol is the ALPN Protocol ID for the ACME-TLS/1 Protocol.
acmeTLS1Protocol = "acme-tls/1" ACMETLS1Protocol = "acme-tls/1"
// defaultTLSPort is the port that the TLSALPNProviderServer will default to // defaultTLSPort is the port that the TLSALPNProviderServer will default to
// when no other port is provided. // 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 // We must set that the `acme-tls/1` application level protocol is supported
// so that the protocol negotiation can succeed. Reference: // so that the protocol negotiation can succeed. Reference:
// https://tools.ietf.org/html/draft-ietf-acme-tls-alpn-01#section-5.2 // 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. // Create the listener with the created tls.Config.
t.listener, err = tls.Listen("tcp", net.JoinHostPort(t.iface, t.port), tlsConf) t.listener, err = tls.Listen("tcp", net.JoinHostPort(t.iface, t.port), tlsConf)