Skip to content

Commit 170757e

Browse files
committed
support p12 certificate format, add param -cert-type and -pass
1 parent c17f078 commit 170757e

File tree

5 files changed

+51
-8
lines changed

5 files changed

+51
-8
lines changed

.gitignore

+1
Original file line numberDiff line numberDiff line change
@@ -2,3 +2,4 @@ dist/
22
.idea/
33
VERSION
44
.tmp/
5+
*.swp

cmd/grpcurl/grpcurl.go

+6-2
Original file line numberDiff line numberDiff line change
@@ -67,6 +67,10 @@ var (
6767
cert = flags.String("cert", "", prettify(`
6868
File containing client certificate (public key), to present to the
6969
server. Not valid with -plaintext option. Must also provide -key option.`))
70+
certType = flags.String("cert-type", "", prettify(`
71+
Client certificate file type. (PEM/P12)`))
72+
pass = flags.String("pass", "", prettify(`
73+
Pass phrase for the key`))
7074
key = flags.String("key", "", prettify(`
7175
File containing client private key, to present to the server. Not valid
7276
with -plaintext option. Must also provide -cert option.`))
@@ -314,7 +318,7 @@ func main() {
314318
if *key != "" && !usetls {
315319
fail(nil, "The -key argument can only be used with TLS.")
316320
}
317-
if (*key == "") != (*cert == "") {
321+
if (*key == "") != (*cert == "") && !strings.EqualFold(*certType, "p12") {
318322
fail(nil, "The -cert and -key arguments must be used together and both be present.")
319323
}
320324
if *altsHandshakerServiceAddress != "" && !*usealts {
@@ -451,7 +455,7 @@ func main() {
451455
}
452456
creds = alts.NewClientCreds(clientOptions)
453457
} else if usetls {
454-
tlsConf, err := grpcurl.ClientTLSConfig(*insecure, *cacert, *cert, *key)
458+
tlsConf, err := grpcurl.ClientTLSConfig(*insecure, *cacert, *cert, *key, *certType, *pass)
455459
if err != nil {
456460
fail(err, "Failed to create TLS config")
457461
}

go.mod

+4-3
Original file line numberDiff line numberDiff line change
@@ -5,6 +5,7 @@ go 1.18
55
require (
66
github.com/golang/protobuf v1.5.3
77
github.com/jhump/protoreflect v1.15.2
8+
golang.org/x/crypto v0.13.0
89
google.golang.org/grpc v1.57.0
910
google.golang.org/protobuf v1.31.0
1011
)
@@ -19,11 +20,11 @@ require (
1920
github.com/cncf/xds/go v0.0.0-20230607035331-e9ce68804cb4 // indirect
2021
github.com/envoyproxy/go-control-plane v0.11.1-0.20230524094728-9239064ad72f // indirect
2122
github.com/envoyproxy/protoc-gen-validate v0.10.1 // indirect
22-
golang.org/x/net v0.9.0 // indirect
23+
golang.org/x/net v0.10.0 // indirect
2324
golang.org/x/oauth2 v0.7.0 // indirect
2425
golang.org/x/sync v0.3.0 // indirect
25-
golang.org/x/sys v0.7.0 // indirect
26-
golang.org/x/text v0.9.0 // indirect
26+
golang.org/x/sys v0.12.0 // indirect
27+
golang.org/x/text v0.13.0 // indirect
2728
google.golang.org/appengine v1.6.7 // indirect
2829
google.golang.org/genproto v0.0.0-20230526161137-0005af68ea54 // indirect
2930
google.golang.org/genproto/googleapis/api v0.0.0-20230525234035-dd9d682886f9 // indirect

go.sum

+8
Original file line numberDiff line numberDiff line change
@@ -46,6 +46,8 @@ github.com/prometheus/client_model v0.0.0-20190812154241-14fe0d1b01d4/go.mod h1:
4646
github.com/spf13/afero v1.3.3/go.mod h1:5KUK8ByomD5Ti5Artl0RtHeI5pTF7MIDuXL3yY520V4=
4747
github.com/stretchr/testify v1.8.4 h1:CcVxjf3Q8PM0mHUKJCdn+eZZtm5yQwehR5yeSVQQcUk=
4848
golang.org/x/crypto v0.0.0-20190308221718-c2843e01d9a2/go.mod h1:djNgcEr1/C05ACkg1iLfiJU5Ep61QUkGW8qpdssI0+w=
49+
golang.org/x/crypto v0.13.0 h1:mvySKfSWJ+UKUii46M40LOvyWfN0s2U+46/jDd0e6Ck=
50+
golang.org/x/crypto v0.13.0/go.mod h1:y6Z2r+Rw4iayiXXAIxJIDAJ1zMW4yaTpebo8fPOliYc=
4951
golang.org/x/exp v0.0.0-20190121172915-509febef88a4/go.mod h1:CJ0aWSM057203Lf6IL+f9T1iT9GByDxfZKAQTCR3kQA=
5052
golang.org/x/lint v0.0.0-20181026193005-c67002cb31c3/go.mod h1:UVdnD1Gm6xHRNCYTkRU2/jEulfH38KcIWyp/GAMgvoE=
5153
golang.org/x/lint v0.0.0-20190227174305-5b3e6a55c961/go.mod h1:wehouNa3lNwaWXcvxsM5YxQ5yQlVC4a0KAMCusXpPoU=
@@ -58,6 +60,8 @@ golang.org/x/net v0.0.0-20190311183353-d8887717615a/go.mod h1:t9HGtf8HONx5eT2rtn
5860
golang.org/x/net v0.0.0-20190603091049-60506f45cf65/go.mod h1:HSz+uSET+XFnRR8LxR5pz3Of3rY3CfYBVs4xY44aLks=
5961
golang.org/x/net v0.9.0 h1:aWJ/m6xSmxWBx+V0XRHTlrYrPG56jKsLdTFmsSsCzOM=
6062
golang.org/x/net v0.9.0/go.mod h1:d48xBJpPfHeWQsugry2m+kC02ZBRGRgulfHnEXEuWns=
63+
golang.org/x/net v0.10.0 h1:X2//UzNDwYmtCLn7To6G58Wr6f5ahEAQgKNzv9Y951M=
64+
golang.org/x/net v0.10.0/go.mod h1:0qNGK6F8kojg2nk9dLZ2mShWaEBan6FAoqfSigmmuDg=
6165
golang.org/x/oauth2 v0.0.0-20180821212333-d2e6202438be/go.mod h1:N/0e6XlmueqKjAGxoOufVs8QHGRruUQn6yWY3a++T0U=
6266
golang.org/x/oauth2 v0.7.0 h1:qe6s0zUXlPX80/dITx3440hWZ7GwMwgDDyrSGTPJG/g=
6367
golang.org/x/oauth2 v0.7.0/go.mod h1:hPLQkd9LyjfXTiRohC/41GhcFqxisoUQ99sCUOHO9x4=
@@ -70,10 +74,14 @@ golang.org/x/sys v0.0.0-20180830151530-49385e6e1522/go.mod h1:STP8DvDyc/dI5b8T5h
7074
golang.org/x/sys v0.0.0-20190215142949-d0b11bdaac8a/go.mod h1:STP8DvDyc/dI5b8T5hshtkjS+E42TnysNCUPdjciGhY=
7175
golang.org/x/sys v0.7.0 h1:3jlCCIQZPdOYu1h8BkNvLz8Kgwtae2cagcG/VamtZRU=
7276
golang.org/x/sys v0.7.0/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg=
77+
golang.org/x/sys v0.12.0 h1:CM0HF96J0hcLAwsHPJZjfdNzs0gftsLfgKt57wWHJ0o=
78+
golang.org/x/sys v0.12.0/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg=
7379
golang.org/x/text v0.3.0/go.mod h1:NqM8EUOU14njkJ3fqMW+pc6Ldnwhi/IjpwHt7yyuwOQ=
7480
golang.org/x/text v0.3.2/go.mod h1:bEr9sfX3Q8Zfm5fL9x+3itogRgK3+ptLWKqgva+5dAk=
7581
golang.org/x/text v0.9.0 h1:2sjJmO8cDvYveuX97RDLsxlyUxLl+GHoLxBiRdHllBE=
7682
golang.org/x/text v0.9.0/go.mod h1:e1OnstbJyHTd6l/uOt8jFFHp6TRDWZR/bV3emEE/zU8=
83+
golang.org/x/text v0.13.0 h1:ablQoSUd0tRdKxZewP80B+BaqeKJuVhuRxj/dkrun3k=
84+
golang.org/x/text v0.13.0/go.mod h1:TvPlkZtksWOMsz7fbANvkp4WM8x/WCo/om8BMLbz+aE=
7785
golang.org/x/tools v0.0.0-20180917221912-90fa682c2a6e/go.mod h1:n7NCudcB/nEzxVGmLbDWY5pfWTLqBcC2KZ6jyYvM4mQ=
7886
golang.org/x/tools v0.0.0-20190114222345-bf090417da8b/go.mod h1:n7NCudcB/nEzxVGmLbDWY5pfWTLqBcC2KZ6jyYvM4mQ=
7987
golang.org/x/tools v0.0.0-20190226205152-f727befe758c/go.mod h1:9Yl7xja0Znq3iFh3HoIrodX9oNMXvdceNzlUR8zjMvY=

grpcurl.go

+32-3
Original file line numberDiff line numberDiff line change
@@ -12,6 +12,7 @@ import (
1212
"crypto/tls"
1313
"crypto/x509"
1414
"encoding/base64"
15+
"encoding/pem"
1516
"errors"
1617
"fmt"
1718
"io/ioutil"
@@ -25,6 +26,7 @@ import (
2526
"github.com/jhump/protoreflect/desc"
2627
"github.com/jhump/protoreflect/desc/protoprint"
2728
"github.com/jhump/protoreflect/dynamic"
29+
"golang.org/x/crypto/pkcs12"
2830
"google.golang.org/grpc"
2931
"google.golang.org/grpc/credentials"
3032
"google.golang.org/grpc/credentials/insecure"
@@ -515,7 +517,7 @@ func makeTemplate(md *desc.MessageDescriptor, path []*desc.MessageDescriptor) pr
515517
//
516518
// Deprecated: Use grpcurl.ClientTLSConfig and credentials.NewTLS instead.
517519
func ClientTransportCredentials(insecureSkipVerify bool, cacertFile, clientCertFile, clientKeyFile string) (credentials.TransportCredentials, error) {
518-
tlsConf, err := ClientTLSConfig(insecureSkipVerify, cacertFile, clientCertFile, clientKeyFile)
520+
tlsConf, err := ClientTLSConfig(insecureSkipVerify, cacertFile, clientCertFile, clientKeyFile, "", "")
519521
if err != nil {
520522
return nil, err
521523
}
@@ -527,12 +529,18 @@ func ClientTransportCredentials(insecureSkipVerify bool, cacertFile, clientCertF
527529
// given properties. If cacertFile is blank, only standard trusted certs are used to
528530
// verify the server certs. If clientCertFile is blank, the client will not use a client
529531
// certificate. If clientCertFile is not blank then clientKeyFile must not be blank.
530-
func ClientTLSConfig(insecureSkipVerify bool, cacertFile, clientCertFile, clientKeyFile string) (*tls.Config, error) {
532+
func ClientTLSConfig(insecureSkipVerify bool, cacertFile, clientCertFile, clientKeyFile, clientCertType, clientPass string) (*tls.Config, error) {
531533
var tlsConf tls.Config
532534

533535
if clientCertFile != "" {
534536
// Load the client certificates from disk
535-
certificate, err := tls.LoadX509KeyPair(clientCertFile, clientKeyFile)
537+
var certificate tls.Certificate
538+
var err error
539+
if strings.EqualFold(clientCertType, "p12") {
540+
certificate, err = loadClientCertP12(clientCertFile, clientPass)
541+
} else {
542+
certificate, err = tls.LoadX509KeyPair(clientCertFile, clientKeyFile)
543+
}
536544
if err != nil {
537545
return nil, fmt.Errorf("could not load client key pair: %v", err)
538546
}
@@ -560,6 +568,27 @@ func ClientTLSConfig(insecureSkipVerify bool, cacertFile, clientCertFile, client
560568
return &tlsConf, nil
561569
}
562570

571+
func loadClientCertP12(pfxFile, pfxPassword string) (tls.Certificate, error) {
572+
b, err := os.ReadFile(pfxFile)
573+
if err != nil {
574+
return tls.Certificate{}, fmt.Errorf("os.ReadFile err: %w", err)
575+
}
576+
pemBlocks, err := pkcs12.ToPEM(b, pfxPassword)
577+
if err != nil {
578+
return tls.Certificate{}, fmt.Errorf("pkcs12.ToPEM err: %w", err)
579+
}
580+
581+
var pemBytes []byte
582+
for _, block := range pemBlocks {
583+
pemBytes = append(pemBytes, pem.EncodeToMemory(block)...)
584+
}
585+
certificate, err := tls.X509KeyPair(pemBytes, pemBytes)
586+
if err != nil {
587+
return tls.Certificate{}, err
588+
}
589+
return certificate, nil
590+
}
591+
563592
// ServerTransportCredentials builds transport credentials for a gRPC server using the
564593
// given properties. If cacertFile is blank, the server will not request client certs
565594
// unless requireClientCerts is true. When requireClientCerts is false and cacertFile is

0 commit comments

Comments
 (0)