tidy code not finished yet
This commit is contained in:
parent
8060fffba3
commit
6f4f86da79
|
|
@ -14,6 +14,7 @@ import (
|
||||||
"strings"
|
"strings"
|
||||||
"time"
|
"time"
|
||||||
|
|
||||||
|
"github.com/fullstorydev/grpcurl/internal/certigo/lib"
|
||||||
"github.com/jhump/protoreflect/desc"
|
"github.com/jhump/protoreflect/desc"
|
||||||
"github.com/jhump/protoreflect/grpcreflect"
|
"github.com/jhump/protoreflect/grpcreflect"
|
||||||
"google.golang.org/grpc"
|
"google.golang.org/grpc"
|
||||||
|
|
@ -64,18 +65,21 @@ var (
|
||||||
cacert = flags.String("cacert", "", prettify(`
|
cacert = flags.String("cacert", "", prettify(`
|
||||||
File containing trusted root certificates for verifying the server.
|
File containing trusted root certificates for verifying the server.
|
||||||
Ignored if -insecure is specified.`))
|
Ignored if -insecure is specified.`))
|
||||||
|
pCACertFormat = flags.String("cacert-format", string(lib.CertKeyFormatPEM), prettify(`
|
||||||
|
cacert Format of given input (PEM, DER; heuristic if missing).`))
|
||||||
cert = flags.String("cert", "", prettify(`
|
cert = flags.String("cert", "", prettify(`
|
||||||
File containing client certificate (public key), to present to the
|
File containing client certificate (public key), to present to the
|
||||||
server. Not valid with -plaintext option. Must also provide -key option
|
server. Not valid with -plaintext option. Must also provide -key option
|
||||||
when use PEM certificate file.`))
|
when use PEM/DER certificate file.`))
|
||||||
certTypeString = flags.String("cert-type", "", prettify(`
|
pCertFormat = flags.String("cert-format", string(lib.CertKeyFormatPEM), prettify(`
|
||||||
Client certificate file type. (PEM/P12)`))
|
cert Format of given input (PEM, DER, PKCS12; heuristic if missing).`))
|
||||||
certType = grpcurl.CertTypePEM
|
pass = flags.String("pass", "", prettify(`
|
||||||
pass = flags.String("pass", "", prettify(`
|
|
||||||
Pass phrase for the key`))
|
Pass phrase for the key`))
|
||||||
key = flags.String("key", "", prettify(`
|
key = flags.String("key", "", prettify(`
|
||||||
File containing client private key, to present to the server. Not valid
|
File containing client private key, to present to the server. Not valid
|
||||||
with -plaintext option. Must also provide -cert option.`))
|
with -plaintext option. Must also provide -cert option.`))
|
||||||
|
pKeyFormat = flags.String("key-format", string(lib.CertKeyFormatPEM), prettify(`
|
||||||
|
key Format of given input (PEM, DER; heuristic if missing).`))
|
||||||
|
|
||||||
// ALTS Options
|
// ALTS Options
|
||||||
usealts = flags.Bool("alts", false, prettify(`
|
usealts = flags.Bool("alts", false, prettify(`
|
||||||
|
|
@ -294,17 +298,9 @@ func main() {
|
||||||
|
|
||||||
// default behavior is to use tls
|
// default behavior is to use tls
|
||||||
usetls := !*plaintext && !*usealts
|
usetls := !*plaintext && !*usealts
|
||||||
|
cacertFormat := lib.NewCertificateKeyFormat(*pCACertFormat)
|
||||||
//// converto to CertificateFileType
|
certFormat := lib.NewCertificateKeyFormat(*pCertFormat)
|
||||||
//if len(*certTypeString) == 0 {
|
keyFormat := lib.NewCertificateKeyFormat(*pKeyFormat)
|
||||||
// certType = grpcurl.CertTypePEM // default PEM
|
|
||||||
//} else if strings.EqualFold(*certTypeString, "PEM") {
|
|
||||||
// certType = grpcurl.CertTypePEM
|
|
||||||
//} else if strings.EqualFold(*certTypeString, "P12") {
|
|
||||||
// certType = grpcurl.CertTypeP12
|
|
||||||
//} else {
|
|
||||||
// fail(nil, "The -cert-type argument must be PEM or P12.")
|
|
||||||
//}
|
|
||||||
|
|
||||||
// Do extra validation on arguments and figure out what user asked us to do.
|
// Do extra validation on arguments and figure out what user asked us to do.
|
||||||
if *connectTimeout < 0 {
|
if *connectTimeout < 0 {
|
||||||
|
|
@ -332,21 +328,61 @@ func main() {
|
||||||
fail(nil, "The -key argument can only be used with TLS.")
|
fail(nil, "The -key argument can only be used with TLS.")
|
||||||
}
|
}
|
||||||
|
|
||||||
//switch certType {
|
if usetls {
|
||||||
//case grpcurl.CertTypePEM:
|
if *cacert != "" {
|
||||||
// if (*key == "") != (*cert == "") {
|
if cacertFormat.IsNone() {
|
||||||
// fail(nil, "The -cert and -key arguments must be used together and both be present when -cert-type is PEM.")
|
guessFormat, err := lib.GuessFormatForFile(*cacert, "")
|
||||||
// }
|
if err != nil {
|
||||||
//case grpcurl.CertTypeP12:
|
fail(nil, "Fail to guess file format of -key err: %s", err)
|
||||||
// if *key != "" {
|
}
|
||||||
// fail(nil, "The -key arguments must not be used when -cert-type is P12.")
|
cacertFormat.Set(guessFormat)
|
||||||
// }
|
}
|
||||||
// if *cert == "" {
|
switch cacertFormat {
|
||||||
// fail(nil, "The -cert arguments must be used when -cert-type is P12.")
|
case lib.CertKeyFormatPEM, lib.CertKeyFormatDER:
|
||||||
// }
|
// do nothing
|
||||||
//default:
|
default:
|
||||||
// fail(nil, "Not support cert type %v.", certType)
|
fail(nil, "The -cacert-format %s not support.", keyFormat)
|
||||||
//}
|
}
|
||||||
|
}
|
||||||
|
if *cert != "" {
|
||||||
|
if certFormat.IsNone() {
|
||||||
|
guessFormat, err := lib.GuessFormatForFile(*cert, "")
|
||||||
|
if err != nil {
|
||||||
|
fail(nil, "Fail to guess file format of -cert err: %s", err)
|
||||||
|
}
|
||||||
|
certFormat.Set(guessFormat)
|
||||||
|
}
|
||||||
|
|
||||||
|
switch certFormat {
|
||||||
|
case lib.CertKeyFormatPEM, lib.CertKeyFormatDER:
|
||||||
|
if *cert == "" || *key == "" {
|
||||||
|
fail(nil, "The -cert and -key arguments must be used together and both be present.")
|
||||||
|
}
|
||||||
|
case lib.CertKeyFormatPKCS12:
|
||||||
|
// do nothing
|
||||||
|
default:
|
||||||
|
fail(nil, "The -cert-format %s not support.", certFormat)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
if *key != "" {
|
||||||
|
if keyFormat.IsNone() {
|
||||||
|
guessFormat, err := lib.GuessFormatForFile(*key, "")
|
||||||
|
if err != nil {
|
||||||
|
fail(nil, "Fail to guess file format of -key err: %s", err)
|
||||||
|
}
|
||||||
|
keyFormat.Set(guessFormat)
|
||||||
|
}
|
||||||
|
switch keyFormat {
|
||||||
|
case lib.CertKeyFormatPEM, lib.CertKeyFormatDER:
|
||||||
|
if *cert == "" || *key == "" {
|
||||||
|
fail(nil, "The -cert and -key arguments must be used together and both be present.")
|
||||||
|
}
|
||||||
|
default:
|
||||||
|
fail(nil, "The -key-format %s not support.", keyFormat)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
}
|
||||||
|
|
||||||
if *altsHandshakerServiceAddress != "" && !*usealts {
|
if *altsHandshakerServiceAddress != "" && !*usealts {
|
||||||
fail(nil, "The -alts-handshaker-service argument must be used with the -alts argument.")
|
fail(nil, "The -alts-handshaker-service argument must be used with the -alts argument.")
|
||||||
|
|
@ -482,7 +518,7 @@ func main() {
|
||||||
}
|
}
|
||||||
creds = alts.NewClientCreds(clientOptions)
|
creds = alts.NewClientCreds(clientOptions)
|
||||||
} else if usetls {
|
} else if usetls {
|
||||||
tlsConf, err := grpcurl.ClientTLSConfigV2(*insecure, *cacert, *cert, *key, certType, *pass)
|
tlsConf, err := lib.ClientTLSConfigV2(*insecure, *cacert, cacertFormat, *cert, certFormat, *key, keyFormat, *pass)
|
||||||
if err != nil {
|
if err != nil {
|
||||||
fail(err, "Failed to create TLS config")
|
fail(err, "Failed to create TLS config")
|
||||||
}
|
}
|
||||||
|
|
|
||||||
68
grpcurl.go
68
grpcurl.go
|
|
@ -526,78 +526,12 @@ func ClientTransportCredentials(insecureSkipVerify bool, cacertFile, clientCertF
|
||||||
return credentials.NewTLS(tlsConf), nil
|
return credentials.NewTLS(tlsConf), nil
|
||||||
}
|
}
|
||||||
|
|
||||||
type CertificateType int
|
|
||||||
|
|
||||||
const (
|
|
||||||
// The certificate file contains PEM encoded data
|
|
||||||
CertTypePEM CertificateType = 1
|
|
||||||
// The certificate file contains PFX data describing PKCS#12.
|
|
||||||
CertTypeP12 CertificateType = 2
|
|
||||||
)
|
|
||||||
|
|
||||||
// ClientTLSConfig builds transport-layer config for a gRPC client using the
|
// ClientTLSConfig builds transport-layer config for a gRPC client using the
|
||||||
// given properties. If cacertFile is blank, only standard trusted certs are used to
|
// given properties. If cacertFile is blank, only standard trusted certs are used to
|
||||||
// verify the server certs. If clientCertFile is blank, the client will not use a client
|
// verify the server certs. If clientCertFile is blank, the client will not use a client
|
||||||
// certificate. If clientCertFile is not blank then clientKeyFile must not be blank.
|
// certificate. If clientCertFile is not blank then clientKeyFile must not be blank.
|
||||||
func ClientTLSConfig(insecureSkipVerify bool, cacertFile, clientCertFile, clientKeyFile string) (*tls.Config, error) {
|
func ClientTLSConfig(insecureSkipVerify bool, cacertFile, clientCertFile, clientKeyFile string) (*tls.Config, error) {
|
||||||
return ClientTLSConfigV2(insecureSkipVerify, cacertFile, clientCertFile, clientKeyFile, CertTypePEM, "")
|
return lib.ClientTLSConfigV2(insecureSkipVerify, cacertFile, lib.CertKeyFormatPEM, clientCertFile, lib.CertKeyFormatPEM, clientKeyFile, lib.CertKeyFormatPEM, "")
|
||||||
}
|
|
||||||
|
|
||||||
// ClientTLSConfigV2 builds transport-layer config for a gRPC client using the
|
|
||||||
// given properties. Support certificate file both PEM and P12.
|
|
||||||
func ClientTLSConfigV2(insecureSkipVerify bool, cacertFile, clientCertFile, clientKeyFile string, clientCertType CertificateType, clientPass string) (*tls.Config, error) {
|
|
||||||
var tlsConf tls.Config
|
|
||||||
|
|
||||||
if clientCertFile != "" {
|
|
||||||
// Load the client certificates from disk
|
|
||||||
clientCertFormat := ""
|
|
||||||
var pemBuf bytes.Buffer
|
|
||||||
err := lib.ReadAsPEMEx(clientCertFile, clientCertFormat, clientPass, func(block *pem.Block, format string) error {
|
|
||||||
return pem.Encode(&pemBuf, block)
|
|
||||||
})
|
|
||||||
if err != nil {
|
|
||||||
return nil, fmt.Errorf("could not load client cert: %v", err)
|
|
||||||
}
|
|
||||||
pemBytes := pemBuf.Bytes()
|
|
||||||
pemKeyBytes := pemBytes
|
|
||||||
|
|
||||||
if clientKeyFile != "" {
|
|
||||||
var pemKeyBuf bytes.Buffer
|
|
||||||
err := lib.ReadAsPEMEx(clientKeyFile, clientCertFormat, clientPass, func(block *pem.Block, format string) error {
|
|
||||||
return pem.Encode(&pemKeyBuf, block)
|
|
||||||
})
|
|
||||||
if err != nil {
|
|
||||||
return nil, fmt.Errorf("could not load client key: %v", err)
|
|
||||||
}
|
|
||||||
pemKeyBytes = pemKeyBuf.Bytes()
|
|
||||||
}
|
|
||||||
|
|
||||||
certificate, err := tls.X509KeyPair(pemBytes, pemKeyBytes)
|
|
||||||
if err != nil {
|
|
||||||
return nil, fmt.Errorf("could not load client key pair: %v", err)
|
|
||||||
}
|
|
||||||
tlsConf.Certificates = []tls.Certificate{certificate}
|
|
||||||
}
|
|
||||||
|
|
||||||
if insecureSkipVerify {
|
|
||||||
tlsConf.InsecureSkipVerify = true
|
|
||||||
} else if cacertFile != "" {
|
|
||||||
// Create a certificate pool from the certificate authority
|
|
||||||
certPool := x509.NewCertPool()
|
|
||||||
ca, err := ioutil.ReadFile(cacertFile)
|
|
||||||
if err != nil {
|
|
||||||
return nil, fmt.Errorf("could not read ca certificate: %v", err)
|
|
||||||
}
|
|
||||||
|
|
||||||
// Append the certificates from the CA
|
|
||||||
if ok := certPool.AppendCertsFromPEM(ca); !ok {
|
|
||||||
return nil, errors.New("failed to append ca certs")
|
|
||||||
}
|
|
||||||
|
|
||||||
tlsConf.RootCAs = certPool
|
|
||||||
}
|
|
||||||
|
|
||||||
return &tlsConf, nil
|
|
||||||
}
|
}
|
||||||
|
|
||||||
func inputFiles(fileNames []string) ([]*os.File, error) {
|
func inputFiles(fileNames []string) ([]*os.File, error) {
|
||||||
|
|
|
||||||
|
|
@ -22,6 +22,7 @@ import (
|
||||||
"crypto"
|
"crypto"
|
||||||
"crypto/ecdsa"
|
"crypto/ecdsa"
|
||||||
"crypto/rsa"
|
"crypto/rsa"
|
||||||
|
"crypto/tls"
|
||||||
"crypto/x509"
|
"crypto/x509"
|
||||||
"encoding/binary"
|
"encoding/binary"
|
||||||
"encoding/pem"
|
"encoding/pem"
|
||||||
|
|
@ -50,6 +51,7 @@ const (
|
||||||
var fileExtToFormat = map[string]string{
|
var fileExtToFormat = map[string]string{
|
||||||
".pem": "PEM",
|
".pem": "PEM",
|
||||||
".crt": "PEM",
|
".crt": "PEM",
|
||||||
|
".cer": "PEM",
|
||||||
".p7b": "PEM",
|
".p7b": "PEM",
|
||||||
".p7c": "PEM",
|
".p7c": "PEM",
|
||||||
".p12": "PKCS12",
|
".p12": "PKCS12",
|
||||||
|
|
@ -84,28 +86,166 @@ func errorFromErrors(errs []error) error {
|
||||||
return errors.New(buffer.String())
|
return errors.New(buffer.String())
|
||||||
}
|
}
|
||||||
|
|
||||||
// ReadAsPEMFromFiles will read PEM blocks from the given set of inputs. Input
|
func NewCertificateKeyFormat(fileFormat string) CertificateKeyFormat {
|
||||||
// data may be in plain-text PEM files, DER-encoded certificates or PKCS7
|
fileFormat = strings.ToUpper(fileFormat)
|
||||||
// envelopes, or PKCS12/JCEKS keystores. All inputs will be converted to PEM
|
switch fileFormat {
|
||||||
// blocks and passed to the callback.
|
case "":
|
||||||
func ReadAsPEMFromFiles(files []*os.File, format string, password func(string) string, callback func(*pem.Block, string) error) error {
|
return CertKeyFormatNONE
|
||||||
var errs []error
|
case "PEM":
|
||||||
for _, file := range files {
|
return CertKeyFormatPEM
|
||||||
reader := bufio.NewReaderSize(file, 4)
|
case "DER":
|
||||||
format, err := formatForFile(reader, file.Name(), format)
|
return CertKeyFormatDER
|
||||||
if err != nil {
|
case "PKCS12", "P12":
|
||||||
return fmt.Errorf("unable to guess file type for file %s", file.Name())
|
return CertKeyFormatPKCS12
|
||||||
}
|
default:
|
||||||
|
return CertKeyFormatNONE
|
||||||
err = readCertsFromStream(reader, file.Name(), format, password, callback)
|
|
||||||
if err != nil {
|
|
||||||
errs = append(errs, err)
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
return errorFromErrors(errs)
|
|
||||||
}
|
}
|
||||||
|
|
||||||
func ReadAsPEMEx(filename string, format string, password string, callback func(*pem.Block, string) error) error {
|
type CertificateKeyFormat string
|
||||||
|
|
||||||
|
const (
|
||||||
|
CertKeyFormatNONE CertificateKeyFormat = ""
|
||||||
|
// The file contains plain-text PEM data
|
||||||
|
CertKeyFormatPEM CertificateKeyFormat = "PEM"
|
||||||
|
// The file contains X.509 DER encoded data
|
||||||
|
CertKeyFormatDER CertificateKeyFormat = "DER"
|
||||||
|
// The file contains JCEKS keystores
|
||||||
|
CertKeyFormatJCEKS CertificateKeyFormat = "JCEKS"
|
||||||
|
// The file contains PFX data describing PKCS#12
|
||||||
|
CertKeyFormatPKCS12 CertificateKeyFormat = "PKCS12"
|
||||||
|
)
|
||||||
|
|
||||||
|
func (f *CertificateKeyFormat) Set(fileFormat string) {
|
||||||
|
*f = NewCertificateKeyFormat(fileFormat)
|
||||||
|
}
|
||||||
|
|
||||||
|
func (f CertificateKeyFormat) IsNone() bool {
|
||||||
|
return f == CertKeyFormatNONE
|
||||||
|
}
|
||||||
|
|
||||||
|
func (f *CertificateKeyFormat) SetPEM() {
|
||||||
|
*f = CertKeyFormatPEM
|
||||||
|
}
|
||||||
|
|
||||||
|
func (f CertificateKeyFormat) IsPEM() bool {
|
||||||
|
return f == CertKeyFormatPEM
|
||||||
|
}
|
||||||
|
|
||||||
|
func (f CertificateKeyFormat) IsDER() bool {
|
||||||
|
return f == CertKeyFormatDER
|
||||||
|
}
|
||||||
|
|
||||||
|
func (f CertificateKeyFormat) IsPKCS12() bool {
|
||||||
|
return f == CertKeyFormatPKCS12
|
||||||
|
}
|
||||||
|
|
||||||
|
// ClientTLSConfigV2 builds transport-layer config for a gRPC client using the
|
||||||
|
// given properties. Support certificate file both PEM and P12.
|
||||||
|
func ClientTLSConfigV2(insecureSkipVerify bool, cacertFile string, cacertFormat CertificateKeyFormat, clientCertFile string, certFormat CertificateKeyFormat, clientKeyFile string, keyFormat CertificateKeyFormat, clientPass string) (*tls.Config, error) {
|
||||||
|
var tlsConf tls.Config
|
||||||
|
|
||||||
|
if clientCertFile != "" {
|
||||||
|
// Load the client certificates
|
||||||
|
pemCertBytes, err := readAsPEMEx2(clientCertFile, string(certFormat), clientPass)
|
||||||
|
if err != nil {
|
||||||
|
return nil, fmt.Errorf("could not load client cert: %v", err)
|
||||||
|
}
|
||||||
|
pemKeyBytes := pemCertBytes // allow clientCertFile include both certificate and key file (JCEKS/PKCS12/PEM)
|
||||||
|
|
||||||
|
// Load the client key
|
||||||
|
if clientKeyFile != "" {
|
||||||
|
pemBytes, err := readAsPEMEx2(clientKeyFile, string(keyFormat), clientPass)
|
||||||
|
if err != nil {
|
||||||
|
return nil, fmt.Errorf("could not load client key: %v", err)
|
||||||
|
}
|
||||||
|
pemKeyBytes = pemBytes
|
||||||
|
}
|
||||||
|
|
||||||
|
// Load tls.Certificate
|
||||||
|
certificate, err := tls.X509KeyPair(pemCertBytes, pemKeyBytes)
|
||||||
|
if err != nil {
|
||||||
|
return nil, fmt.Errorf("could not load client key pair: %v", err)
|
||||||
|
}
|
||||||
|
tlsConf.Certificates = []tls.Certificate{certificate}
|
||||||
|
}
|
||||||
|
|
||||||
|
if insecureSkipVerify {
|
||||||
|
tlsConf.InsecureSkipVerify = true
|
||||||
|
} else if cacertFile != "" {
|
||||||
|
// Create a certificate pool from the certificate authority
|
||||||
|
certPool := x509.NewCertPool()
|
||||||
|
pemCACertBytes, err := readAsPEMEx2(cacertFile, string(cacertFormat), "")
|
||||||
|
if err != nil {
|
||||||
|
return nil, fmt.Errorf("could not load cacert : %v", err)
|
||||||
|
}
|
||||||
|
|
||||||
|
// Append the certificates from the CA
|
||||||
|
if ok := certPool.AppendCertsFromPEM(pemCACertBytes); !ok {
|
||||||
|
return nil, errors.New("failed to append ca certs")
|
||||||
|
}
|
||||||
|
|
||||||
|
tlsConf.RootCAs = certPool
|
||||||
|
}
|
||||||
|
|
||||||
|
return &tlsConf, nil
|
||||||
|
}
|
||||||
|
|
||||||
|
func GuessFormatForFile(filename, format string) (string, error) {
|
||||||
|
// Second, attempt to guess based on extension
|
||||||
|
guess, ok := fileExtToFormat[strings.ToLower(filepath.Ext(filename))]
|
||||||
|
if ok {
|
||||||
|
return guess, nil
|
||||||
|
}
|
||||||
|
|
||||||
|
file, err := os.Open(filename)
|
||||||
|
if err != nil {
|
||||||
|
return "", fmt.Errorf("unable to open file: %s\n", err)
|
||||||
|
}
|
||||||
|
defer file.Close()
|
||||||
|
reader := bufio.NewReaderSize(file, 4)
|
||||||
|
|
||||||
|
// Third, attempt to guess based on first 4 bytes of input
|
||||||
|
data, err := reader.Peek(4)
|
||||||
|
if err != nil {
|
||||||
|
return "", fmt.Errorf("unable to read file: %s\n", err)
|
||||||
|
}
|
||||||
|
|
||||||
|
// Heuristics for guessing -- best effort.
|
||||||
|
magic := binary.BigEndian.Uint32(data)
|
||||||
|
if magic == 0xCECECECE || magic == 0xFEEDFEED {
|
||||||
|
// JCEKS/JKS files always start with this prefix
|
||||||
|
return "JCEKS", nil
|
||||||
|
}
|
||||||
|
if magic == 0x2D2D2D2D || magic == 0x434f4e4e {
|
||||||
|
// Starts with '----' or 'CONN' (what s_client prints...)
|
||||||
|
// TODO start with 'Certificate'
|
||||||
|
return "PEM", nil
|
||||||
|
}
|
||||||
|
if magic&0xFFFF0000 == 0x30820000 {
|
||||||
|
// Looks like the input is DER-encoded, so it's either PKCS12 or X.509.
|
||||||
|
if magic&0x0000FF00 == 0x0300 {
|
||||||
|
// Probably X.509
|
||||||
|
return "DER", nil
|
||||||
|
}
|
||||||
|
return "PKCS12", nil
|
||||||
|
}
|
||||||
|
|
||||||
|
return "", nil
|
||||||
|
}
|
||||||
|
|
||||||
|
func readAsPEMEx2(filename string, format string, password string) ([]byte, error) {
|
||||||
|
var pembuf bytes.Buffer
|
||||||
|
err := readAsPEMEx(filename, format, "", func(block *pem.Block, format string) error {
|
||||||
|
return pem.Encode(&pembuf, block)
|
||||||
|
})
|
||||||
|
if err != nil {
|
||||||
|
return nil, fmt.Errorf("could not load client cert: %v", err)
|
||||||
|
}
|
||||||
|
return pembuf.Bytes(), nil
|
||||||
|
}
|
||||||
|
|
||||||
|
func readAsPEMEx(filename string, format string, password string, callback func(*pem.Block, string) error) error {
|
||||||
rawFile, err := os.Open(filename)
|
rawFile, err := os.Open(filename)
|
||||||
if err != nil {
|
if err != nil {
|
||||||
return fmt.Errorf("unable to open file: %s\n", err)
|
return fmt.Errorf("unable to open file: %s\n", err)
|
||||||
|
|
@ -114,9 +254,39 @@ func ReadAsPEMEx(filename string, format string, password string, callback func(
|
||||||
passwordFunc := func(promet string) string {
|
passwordFunc := func(promet string) string {
|
||||||
return password
|
return password
|
||||||
}
|
}
|
||||||
return ReadAsPEM([]io.Reader{rawFile}, format, passwordFunc, callback)
|
|
||||||
|
reader := bufio.NewReaderSize(rawFile, 4)
|
||||||
|
format, err = formatForFile(reader, "", format)
|
||||||
|
if err != nil {
|
||||||
|
return fmt.Errorf("unable to guess format for input stream")
|
||||||
|
}
|
||||||
|
|
||||||
|
return readCertsFromStream(reader, "", format, passwordFunc, callback)
|
||||||
}
|
}
|
||||||
|
|
||||||
|
// // ReadAsPEMFromFiles will read PEM blocks from the given set of inputs. Input
|
||||||
|
// // data may be in plain-text PEM files, DER-encoded certificates or PKCS7
|
||||||
|
// // envelopes, or PKCS12/JCEKS keystores. All inputs will be converted to PEM
|
||||||
|
// // blocks and passed to the callback.
|
||||||
|
//
|
||||||
|
// func ReadAsPEMFromFiles(files []*os.File, format string, password func(string) string, callback func(*pem.Block, string) error) error {
|
||||||
|
// var errs []error
|
||||||
|
// for _, file := range files {
|
||||||
|
// reader := bufio.NewReaderSize(file, 4)
|
||||||
|
// format, err := formatForFile(reader, file.Name(), format)
|
||||||
|
// if err != nil {
|
||||||
|
// return fmt.Errorf("unable to guess file type for file %s", file.Name())
|
||||||
|
// }
|
||||||
|
//
|
||||||
|
// err = readCertsFromStream(reader, file.Name(), format, password, callback)
|
||||||
|
// if err != nil {
|
||||||
|
// errs = append(errs, err)
|
||||||
|
// }
|
||||||
|
// }
|
||||||
|
// return errorFromErrors(errs)
|
||||||
|
// }
|
||||||
|
//
|
||||||
|
|
||||||
// ReadAsPEM will read PEM blocks from the given set of inputs. Input data may
|
// ReadAsPEM will read PEM blocks from the given set of inputs. Input data may
|
||||||
// be in plain-text PEM files, DER-encoded certificates or PKCS7 envelopes, or
|
// be in plain-text PEM files, DER-encoded certificates or PKCS7 envelopes, or
|
||||||
// PKCS12/JCEKS keystores. All inputs will be converted to PEM blocks and
|
// PKCS12/JCEKS keystores. All inputs will be converted to PEM blocks and
|
||||||
|
|
@ -138,76 +308,76 @@ func ReadAsPEM(readers []io.Reader, format string, password func(string) string,
|
||||||
return errorFromErrors(errs)
|
return errorFromErrors(errs)
|
||||||
}
|
}
|
||||||
|
|
||||||
// ReadAsX509FromFiles will read X.509 certificates from the given set of
|
//// ReadAsX509FromFiles will read X.509 certificates from the given set of
|
||||||
// inputs. Input data may be in plain-text PEM files, DER-encoded certificates
|
//// inputs. Input data may be in plain-text PEM files, DER-encoded certificates
|
||||||
// or PKCS7 envelopes, or PKCS12/JCEKS keystores. All inputs will be converted
|
//// or PKCS7 envelopes, or PKCS12/JCEKS keystores. All inputs will be converted
|
||||||
// to X.509 certificates (private keys are skipped) and passed to the callback.
|
//// to X.509 certificates (private keys are skipped) and passed to the callback.
|
||||||
func ReadAsX509FromFiles(files []*os.File, format string, password func(string) string, callback func(*x509.Certificate, string, error) error) error {
|
//func ReadAsX509FromFiles(files []*os.File, format string, password func(string) string, callback func(*x509.Certificate, string, error) error) error {
|
||||||
errs := []error{}
|
// errs := []error{}
|
||||||
for _, file := range files {
|
// for _, file := range files {
|
||||||
reader := bufio.NewReaderSize(file, 4)
|
// reader := bufio.NewReaderSize(file, 4)
|
||||||
format, err := formatForFile(reader, file.Name(), format)
|
// format, err := formatForFile(reader, file.Name(), format)
|
||||||
if err != nil {
|
// if err != nil {
|
||||||
return fmt.Errorf("unable to guess file type for file %s, try adding --format flag", file.Name())
|
// return fmt.Errorf("unable to guess file type for file %s, try adding --format flag", file.Name())
|
||||||
}
|
// }
|
||||||
|
//
|
||||||
err = readCertsFromStream(reader, file.Name(), format, password, pemToX509(callback))
|
// err = readCertsFromStream(reader, file.Name(), format, password, pemToX509(callback))
|
||||||
if err != nil {
|
// if err != nil {
|
||||||
errs = append(errs, err)
|
// errs = append(errs, err)
|
||||||
}
|
// }
|
||||||
}
|
// }
|
||||||
return errorFromErrors(errs)
|
// return errorFromErrors(errs)
|
||||||
}
|
//}
|
||||||
|
//
|
||||||
// ReadAsX509 will read X.509 certificates from the given set of inputs. Input
|
//// ReadAsX509 will read X.509 certificates from the given set of inputs. Input
|
||||||
// data may be in plain-text PEM files, DER-encoded certificates or PKCS7
|
//// data may be in plain-text PEM files, DER-encoded certificates or PKCS7
|
||||||
// envelopes, or PKCS12/JCEKS keystores. All inputs will be converted to X.509
|
//// envelopes, or PKCS12/JCEKS keystores. All inputs will be converted to X.509
|
||||||
// certificates (private keys are skipped) and passed to the callback.
|
//// certificates (private keys are skipped) and passed to the callback.
|
||||||
func ReadAsX509(readers []io.Reader, format string, password func(string) string, callback func(*x509.Certificate, string, error) error) error {
|
//func ReadAsX509(readers []io.Reader, format string, password func(string) string, callback func(*x509.Certificate, string, error) error) error {
|
||||||
errs := []error{}
|
// errs := []error{}
|
||||||
for _, r := range readers {
|
// for _, r := range readers {
|
||||||
reader := bufio.NewReaderSize(r, 4)
|
// reader := bufio.NewReaderSize(r, 4)
|
||||||
format, err := formatForFile(reader, "", format)
|
// format, err := formatForFile(reader, "", format)
|
||||||
if err != nil {
|
// if err != nil {
|
||||||
return fmt.Errorf("unable to guess format for input stream")
|
// return fmt.Errorf("unable to guess format for input stream")
|
||||||
}
|
// }
|
||||||
|
//
|
||||||
err = readCertsFromStream(reader, "", format, password, pemToX509(callback))
|
// err = readCertsFromStream(reader, "", format, password, pemToX509(callback))
|
||||||
if err != nil {
|
// if err != nil {
|
||||||
errs = append(errs, err)
|
// errs = append(errs, err)
|
||||||
}
|
// }
|
||||||
}
|
// }
|
||||||
return errorFromErrors(errs)
|
// return errorFromErrors(errs)
|
||||||
}
|
//}
|
||||||
|
//
|
||||||
func pemToX509(callback func(*x509.Certificate, string, error) error) func(*pem.Block, string) error {
|
//func pemToX509(callback func(*x509.Certificate, string, error) error) func(*pem.Block, string) error {
|
||||||
return func(block *pem.Block, format string) error {
|
// return func(block *pem.Block, format string) error {
|
||||||
switch block.Type {
|
// switch block.Type {
|
||||||
case "CERTIFICATE":
|
// case "CERTIFICATE":
|
||||||
cert, err := x509.ParseCertificate(block.Bytes)
|
// cert, err := x509.ParseCertificate(block.Bytes)
|
||||||
return callback(cert, format, err)
|
// return callback(cert, format, err)
|
||||||
case "PKCS7":
|
// case "PKCS7":
|
||||||
certs, err := pkcs7.ExtractCertificates(block.Bytes)
|
// certs, err := pkcs7.ExtractCertificates(block.Bytes)
|
||||||
if err == nil {
|
// if err == nil {
|
||||||
for _, cert := range certs {
|
// for _, cert := range certs {
|
||||||
return callback(cert, format, nil)
|
// return callback(cert, format, nil)
|
||||||
}
|
// }
|
||||||
} else {
|
// } else {
|
||||||
return callback(nil, format, err)
|
// return callback(nil, format, err)
|
||||||
}
|
// }
|
||||||
case "CERTIFICATE REQUEST":
|
// case "CERTIFICATE REQUEST":
|
||||||
fmt.Println("warning: certificate requests are not supported")
|
// fmt.Println("warning: certificate requests are not supported")
|
||||||
}
|
// }
|
||||||
return nil
|
// return nil
|
||||||
}
|
// }
|
||||||
}
|
//}
|
||||||
|
//
|
||||||
func ReadCertsFromStream(reader io.Reader, filename string, format string, password string, callback func(*pem.Block, string) error) error {
|
//func ReadCertsFromStream(reader io.Reader, filename string, format string, password string, callback func(*pem.Block, string) error) error {
|
||||||
passwordFunc := func(promet string) string {
|
// passwordFunc := func(promet string) string {
|
||||||
return password
|
// return password
|
||||||
}
|
// }
|
||||||
return readCertsFromStream(reader, filename, format, passwordFunc, callback)
|
// return readCertsFromStream(reader, filename, format, passwordFunc, callback)
|
||||||
}
|
//}
|
||||||
|
|
||||||
// readCertsFromStream takes some input and converts it to PEM blocks.
|
// readCertsFromStream takes some input and converts it to PEM blocks.
|
||||||
func readCertsFromStream(reader io.Reader, filename string, format string, password func(string) string, callback func(*pem.Block, string) error) error {
|
func readCertsFromStream(reader io.Reader, filename string, format string, password func(string) string, callback func(*pem.Block, string) error) error {
|
||||||
|
|
@ -237,7 +407,7 @@ func readCertsFromStream(reader io.Reader, filename string, format string, passw
|
||||||
x509Certs, err0 := x509.ParseCertificates(data)
|
x509Certs, err0 := x509.ParseCertificates(data)
|
||||||
if err0 == nil {
|
if err0 == nil {
|
||||||
for _, cert := range x509Certs {
|
for _, cert := range x509Certs {
|
||||||
err := callback(EncodeX509ToPEM(cert, headers), format)
|
err := callback(encodeX509ToPEM(cert, headers), format)
|
||||||
if err != nil {
|
if err != nil {
|
||||||
return err
|
return err
|
||||||
}
|
}
|
||||||
|
|
@ -279,7 +449,7 @@ func readCertsFromStream(reader io.Reader, filename string, format string, passw
|
||||||
}
|
}
|
||||||
for _, alias := range keyStore.ListCerts() {
|
for _, alias := range keyStore.ListCerts() {
|
||||||
cert, _ := keyStore.GetCert(alias)
|
cert, _ := keyStore.GetCert(alias)
|
||||||
err := callback(EncodeX509ToPEM(cert, mergeHeaders(headers, map[string]string{nameHeader: alias})), format)
|
err := callback(encodeX509ToPEM(cert, mergeHeaders(headers, map[string]string{nameHeader: alias})), format)
|
||||||
if err != nil {
|
if err != nil {
|
||||||
return err
|
return err
|
||||||
}
|
}
|
||||||
|
|
@ -302,7 +472,7 @@ func readCertsFromStream(reader io.Reader, filename string, format string, passw
|
||||||
}
|
}
|
||||||
|
|
||||||
for _, cert := range certs {
|
for _, cert := range certs {
|
||||||
if err = callback(EncodeX509ToPEM(cert, mergedHeaders), format); err != nil {
|
if err = callback(encodeX509ToPEM(cert, mergedHeaders), format); err != nil {
|
||||||
return err
|
return err
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
@ -323,8 +493,8 @@ func mergeHeaders(baseHeaders, extraHeaders map[string]string) (headers map[stri
|
||||||
return
|
return
|
||||||
}
|
}
|
||||||
|
|
||||||
// EncodeX509ToPEM converts an X.509 certificate into a PEM block for output.
|
// encodeX509ToPEM converts an X.509 certificate into a PEM block for output.
|
||||||
func EncodeX509ToPEM(cert *x509.Certificate, headers map[string]string) *pem.Block {
|
func encodeX509ToPEM(cert *x509.Certificate, headers map[string]string) *pem.Block {
|
||||||
return &pem.Block{
|
return &pem.Block{
|
||||||
Type: "CERTIFICATE",
|
Type: "CERTIFICATE",
|
||||||
Bytes: cert.Raw,
|
Bytes: cert.Raw,
|
||||||
|
|
@ -392,6 +562,7 @@ func formatForFile(file *bufio.Reader, filename, format string) (string, error)
|
||||||
}
|
}
|
||||||
if magic == 0x2D2D2D2D || magic == 0x434f4e4e {
|
if magic == 0x2D2D2D2D || magic == 0x434f4e4e {
|
||||||
// Starts with '----' or 'CONN' (what s_client prints...)
|
// Starts with '----' or 'CONN' (what s_client prints...)
|
||||||
|
// TODO start with 'Certificate'
|
||||||
return "PEM", nil
|
return "PEM", nil
|
||||||
}
|
}
|
||||||
if magic&0xFFFF0000 == 0x30820000 {
|
if magic&0xFFFF0000 == 0x30820000 {
|
||||||
|
|
|
||||||
Loading…
Reference in New Issue