sing-box/transport/cloudflaretls/generate_delegated_credential.go

127 lines
3.7 KiB
Go
Raw Normal View History

2022-09-03 15:21:35 +00:00
// Copyright 2022 Cloudflare, Inc. All rights reserved. Use of this source code
// is governed by a BSD-style license that can be found in the LICENSE file.
//go:build ignore
// Generate a delegated credential with the given signature scheme, signed with
// the given x.509 key pair. Outputs to 'dc.cred' and 'dckey.pem' and will
// overwrite existing files.
// Example usage:
// generate_delegated_credential -cert-path cert.pem -key-path key.pem -signature-scheme Ed25519 -duration 24h
package main
import (
"crypto"
"crypto/ecdsa"
"crypto/ed25519"
"crypto/rsa"
"crypto/tls"
"crypto/x509"
"encoding/pem"
"errors"
"flag"
"fmt"
"log"
"os"
"path/filepath"
"time"
circlSign "github.com/cloudflare/circl/sign"
)
var (
validFor = flag.Duration("duration", 5*24*time.Hour, "Duration that credential is valid for")
signatureScheme = flag.String("signature-scheme", "", "The signature scheme used by the DC")
certPath = flag.String("cert-path", "./cert.pem", "Path to signing cert")
keyPath = flag.String("key-path", "./key.pem", "Path to signing key")
isClient = flag.Bool("client-dc", false, "Create a client Delegated Credential")
outPath = flag.String("out-path", "./", "Path to output directory")
)
var SigStringMap = map[string]tls.SignatureScheme{
// ECDSA algorithms. Only constrained to a specific curve in TLS 1.3.
"ECDSAWithP256AndSHA256": tls.ECDSAWithP256AndSHA256,
"ECDSAWithP384AndSHA384": tls.ECDSAWithP384AndSHA384,
"ECDSAWithP521AndSHA512": tls.ECDSAWithP521AndSHA512,
// EdDSA algorithms.
"Ed25519": tls.Ed25519,
}
func main() {
flag.Parse()
sa := SigStringMap[*signatureScheme]
cert, err := tls.LoadX509KeyPair(*certPath, *keyPath)
if err != nil {
log.Fatalf("Failed to load certificate and key: %v", err)
}
cert.Leaf, err = x509.ParseCertificate(cert.Certificate[0])
if err != nil {
log.Fatalf("Failed to parse leaf certificate: %v", err)
}
validTime := time.Since(cert.Leaf.NotBefore) + *validFor
dc, priv, err := tls.NewDelegatedCredential(&cert, sa, validTime, *isClient)
if err != nil {
log.Fatalf("Failed to create a DC: %v\n", err)
}
dcBytes, err := dc.Marshal()
if err != nil {
log.Fatalf("Failed to marshal DC: %v\n", err)
}
DCOut, err := os.Create(filepath.Join(*outPath, "dc.cred"))
if err != nil {
log.Fatalf("Failed to open dc.cred for writing: %v", err)
}
DCOut.Write(dcBytes)
if err := DCOut.Close(); err != nil {
log.Fatalf("Error closing dc.cred: %v", err)
}
log.Print("wrote dc.cred\n")
derBytes, err := x509.MarshalPKCS8PrivateKey(priv)
if err != nil {
log.Fatalf("Failed to marshal DC private key: %v\n", err)
}
DCKeyOut, err := os.Create(filepath.Join(*outPath, "dckey.pem"))
if err != nil {
log.Fatalf("Failed to open dckey.pem for writing: %v", err)
}
if err := pem.Encode(DCKeyOut, &pem.Block{Type: "PRIVATE KEY", Bytes: derBytes}); err != nil {
log.Fatalf("Failed to write data to dckey.pem: %v\n", err)
}
if err := DCKeyOut.Close(); err != nil {
log.Fatalf("Error closing dckey.pem: %v\n", err)
}
log.Print("wrote dckey.pem\n")
fmt.Println("Success")
}
// Copied from tls.go, because it's private.
func parsePrivateKey(der []byte) (crypto.PrivateKey, error) {
if key, err := x509.ParsePKCS1PrivateKey(der); err == nil {
return key, nil
}
if key, err := x509.ParsePKCS8PrivateKey(der); err == nil {
switch key := key.(type) {
case *rsa.PrivateKey, *ecdsa.PrivateKey, ed25519.PrivateKey, circlSign.PrivateKey:
return key, nil
default:
return nil, errors.New("tls: found unknown private key type in PKCS#8 wrapping")
}
}
if key, err := x509.ParseECPrivateKey(der); err == nil {
return key, nil
}
return nil, errors.New("tls: failed to parse private key")
}