* use certmagic for more extensible/robust ACME cert handling * accept TOS based on config option Signed-off-by: Andrew Thornton <art27@cantab.net> Co-authored-by: zeripath <art27@cantab.net> Co-authored-by: Lauris BH <lauris@nix.lv>
		
			
				
	
	
		
			99 lines
		
	
	
		
			3.1 KiB
		
	
	
	
		
			Go
		
	
	
	
		
			Vendored
		
	
	
	
			
		
		
	
	
			99 lines
		
	
	
		
			3.1 KiB
		
	
	
	
		
			Go
		
	
	
	
		
			Vendored
		
	
	
	
| // Copyright 2020 Matthew Holt
 | |
| //
 | |
| // Licensed under the Apache License, Version 2.0 (the "License");
 | |
| // you may not use this file except in compliance with the License.
 | |
| // You may obtain a copy of the License at
 | |
| //
 | |
| //     http://www.apache.org/licenses/LICENSE-2.0
 | |
| //
 | |
| // Unless required by applicable law or agreed to in writing, software
 | |
| // distributed under the License is distributed on an "AS IS" BASIS,
 | |
| // WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
 | |
| // See the License for the specific language governing permissions and
 | |
| // limitations under the License.
 | |
| 
 | |
| package acmez
 | |
| 
 | |
| import (
 | |
| 	"crypto/ecdsa"
 | |
| 	"crypto/elliptic"
 | |
| 	"crypto/rand"
 | |
| 	"crypto/sha256"
 | |
| 	"crypto/tls"
 | |
| 	"crypto/x509"
 | |
| 	"crypto/x509/pkix"
 | |
| 	"encoding/asn1"
 | |
| 	"encoding/pem"
 | |
| 	"math/big"
 | |
| 	"time"
 | |
| 
 | |
| 	"github.com/mholt/acmez/acme"
 | |
| )
 | |
| 
 | |
| // TLSALPN01ChallengeCert creates a certificate that can be used for
 | |
| // handshakes while solving the tls-alpn-01 challenge. See RFC 8737 §3.
 | |
| func TLSALPN01ChallengeCert(challenge acme.Challenge) (*tls.Certificate, error) {
 | |
| 	keyAuthSum := sha256.Sum256([]byte(challenge.KeyAuthorization))
 | |
| 	keyAuthSumASN1, err := asn1.Marshal(keyAuthSum[:sha256.Size])
 | |
| 	if err != nil {
 | |
| 		return nil, err
 | |
| 	}
 | |
| 
 | |
| 	certKey, err := ecdsa.GenerateKey(elliptic.P256(), rand.Reader)
 | |
| 	if err != nil {
 | |
| 		return nil, err
 | |
| 	}
 | |
| 	challengeKeyASN1, err := x509.MarshalECPrivateKey(certKey)
 | |
| 	if err != nil {
 | |
| 		return nil, err
 | |
| 	}
 | |
| 
 | |
| 	serialNumberLimit := new(big.Int).Lsh(big.NewInt(1), 128)
 | |
| 	serialNumber, err := rand.Int(rand.Reader, serialNumberLimit)
 | |
| 	if err != nil {
 | |
| 		return nil, err
 | |
| 	}
 | |
| 	template := x509.Certificate{
 | |
| 		SerialNumber:          serialNumber,
 | |
| 		Subject:               pkix.Name{CommonName: "ACME challenge"},
 | |
| 		NotBefore:             time.Now(),
 | |
| 		NotAfter:              time.Now().Add(24 * time.Hour * 365),
 | |
| 		ExtKeyUsage:           []x509.ExtKeyUsage{x509.ExtKeyUsageServerAuth},
 | |
| 		BasicConstraintsValid: true,
 | |
| 		DNSNames:              []string{challenge.Identifier.Value},
 | |
| 
 | |
| 		// add key authentication digest as the acmeValidation-v1 extension
 | |
| 		// (marked as critical such that it won't be used by non-ACME software).
 | |
| 		// Reference: https://www.rfc-editor.org/rfc/rfc8737.html#section-3
 | |
| 		ExtraExtensions: []pkix.Extension{
 | |
| 			{
 | |
| 				Id:       idPEACMEIdentifierV1,
 | |
| 				Critical: true,
 | |
| 				Value:    keyAuthSumASN1,
 | |
| 			},
 | |
| 		},
 | |
| 	}
 | |
| 	challengeCertDER, err := x509.CreateCertificate(rand.Reader, &template, &template, &certKey.PublicKey, certKey)
 | |
| 	if err != nil {
 | |
| 		return nil, err
 | |
| 	}
 | |
| 
 | |
| 	challengeCertPEM := pem.EncodeToMemory(&pem.Block{Type: "CERTIFICATE", Bytes: challengeCertDER})
 | |
| 	challengeKeyPEM := pem.EncodeToMemory(&pem.Block{Type: "EC PRIVATE KEY", Bytes: challengeKeyASN1})
 | |
| 
 | |
| 	cert, err := tls.X509KeyPair(challengeCertPEM, challengeKeyPEM)
 | |
| 	if err != nil {
 | |
| 		return nil, err
 | |
| 	}
 | |
| 
 | |
| 	return &cert, nil
 | |
| }
 | |
| 
 | |
| // ACMETLS1Protocol is the ALPN value for the TLS-ALPN challenge
 | |
| // handshake. See RFC 8737 §6.2.
 | |
| const ACMETLS1Protocol = "acme-tls/1"
 | |
| 
 | |
| // idPEACMEIdentifierV1 is the SMI Security for PKIX Certification Extension OID referencing the ACME extension.
 | |
| // See RFC 8737 §6.1. https://www.rfc-editor.org/rfc/rfc8737.html#section-6.1
 | |
| var idPEACMEIdentifierV1 = asn1.ObjectIdentifier{1, 3, 6, 1, 5, 5, 7, 1, 31}
 |