mirror of
https://github.com/pion/webrtc.git
synced 2025-09-26 19:21:12 +08:00
Update CertificateFromPEM to support OpenSSL
Update CertificateFromPEM to be a loop over the PEM blocks. This allows decoding the private key before decoding the certificate. Tries to parse the certificate block directly but if that errors, then it also tries to base64 decode the certificate block. Fixes #3042
This commit is contained in:
@@ -191,33 +191,55 @@ func (c Certificate) collectStats(report *statsReportCollector) error {
|
||||
|
||||
// CertificateFromPEM creates a fresh certificate based on a string containing
|
||||
// pem blocks fort the private key and x509 certificate.
|
||||
func CertificateFromPEM(pems string) (*Certificate, error) {
|
||||
// decode & parse the certificate
|
||||
block, more := pem.Decode([]byte(pems))
|
||||
if block == nil || block.Type != "CERTIFICATE" {
|
||||
return nil, errCertificatePEMFormatError
|
||||
}
|
||||
certBytes := make([]byte, base64.StdEncoding.DecodedLen(len(block.Bytes)))
|
||||
n, err := base64.StdEncoding.Decode(certBytes, block.Bytes)
|
||||
if err != nil {
|
||||
return nil, fmt.Errorf("failed to decode ceritifcate: %w", err)
|
||||
}
|
||||
cert, err := x509.ParseCertificate(certBytes[:n])
|
||||
if err != nil {
|
||||
return nil, fmt.Errorf("failed parsing ceritifcate: %w", err)
|
||||
}
|
||||
// decode & parse the private key
|
||||
block, _ = pem.Decode(more)
|
||||
if block == nil || block.Type != "PRIVATE KEY" {
|
||||
return nil, errCertificatePEMFormatError
|
||||
}
|
||||
privateKey, err := x509.ParsePKCS8PrivateKey(block.Bytes)
|
||||
if err != nil {
|
||||
return nil, fmt.Errorf("unable to parse private key: %w", err)
|
||||
}
|
||||
x := CertificateFromX509(privateKey, cert)
|
||||
func CertificateFromPEM(pems string) (*Certificate, error) { //nolint: cyclop
|
||||
var cert *x509.Certificate
|
||||
var privateKey crypto.PrivateKey
|
||||
|
||||
return &x, nil
|
||||
var block *pem.Block
|
||||
more := []byte(pems)
|
||||
for {
|
||||
var err error
|
||||
block, more = pem.Decode(more)
|
||||
if block == nil {
|
||||
break
|
||||
}
|
||||
|
||||
// decode & parse the certificate
|
||||
switch block.Type {
|
||||
case "CERTIFICATE":
|
||||
if cert != nil {
|
||||
return nil, errCertificatePEMMultipleCert
|
||||
}
|
||||
cert, err = x509.ParseCertificate(block.Bytes)
|
||||
// If parsing failed using block.Bytes, then parse the bytes as base64 and try again
|
||||
if err != nil {
|
||||
var n int
|
||||
certBytes := make([]byte, base64.StdEncoding.DecodedLen(len(block.Bytes)))
|
||||
n, err = base64.StdEncoding.Decode(certBytes, block.Bytes)
|
||||
if err == nil {
|
||||
cert, err = x509.ParseCertificate(certBytes[:n])
|
||||
}
|
||||
}
|
||||
case "PRIVATE KEY":
|
||||
if privateKey != nil {
|
||||
return nil, errCertificatePEMMultiplePriv
|
||||
}
|
||||
privateKey, err = x509.ParsePKCS8PrivateKey(block.Bytes)
|
||||
}
|
||||
|
||||
// Report errors from parsing either the private key or the certificate
|
||||
if err != nil {
|
||||
return nil, fmt.Errorf("failed to decode %s: %w", block.Type, err)
|
||||
}
|
||||
}
|
||||
|
||||
if cert == nil || privateKey == nil {
|
||||
return nil, errCertificatePEMMissing
|
||||
}
|
||||
|
||||
ret := CertificateFromX509(privateKey, cert)
|
||||
|
||||
return &ret, nil
|
||||
}
|
||||
|
||||
// PEM returns the certificate encoded as two pem block: once for the X509
|
||||
|
@@ -136,3 +136,57 @@ func TestPEM(t *testing.T) {
|
||||
assert.Nil(t, err)
|
||||
assert.Equal(t, pem, pem2)
|
||||
}
|
||||
|
||||
const (
|
||||
certHeader = `!! This is a test certificate: Don't use it in production !!
|
||||
You can create your own using openssl
|
||||
` + "```sh" + `
|
||||
openssl req -new -sha256 -newkey ec -pkeyopt ec_paramgen_curve:prime256v1 ` +
|
||||
`-x509 -nodes -days 365 -out cert.pem -keyout cert.pem -subj "/CN=WebRTC"
|
||||
openssl x509 -in cert.pem -noout -fingerprint -sha256
|
||||
` + "```\n"
|
||||
|
||||
certPriv = `-----BEGIN PRIVATE KEY-----
|
||||
MIGHAgEAMBMGByqGSM49AgEGCCqGSM49AwEHBG0wawIBAQQg2XFaTNqFpTUqNtG9
|
||||
A21MEe04JtsWVpUTDD8nI0KvchKhRANCAAS1nqME3jS5GFicwYfGDYaz7oSINwWm
|
||||
X4BkfsSCxMrhr7mPtfxOi4Lxy/P3w6EvSSEU8t5E9ouKIWh5xPS9dYwu
|
||||
-----END PRIVATE KEY-----
|
||||
`
|
||||
|
||||
certCert = `-----BEGIN CERTIFICATE-----
|
||||
MIIBljCCATugAwIBAgIUQa1sD+5HG43K+hCEVZLYxB68/hQwCgYIKoZIzj0EAwIw
|
||||
IDEeMBwGA1UEAwwVc3dpdGNoLmV2YW4tYnJhc3MubmV0MB4XDTI0MDQyNDIwMjEy
|
||||
MFoXDTI1MDQyNDIwMjEyMFowIDEeMBwGA1UEAwwVc3dpdGNoLmV2YW4tYnJhc3Mu
|
||||
bmV0MFkwEwYHKoZIzj0CAQYIKoZIzj0DAQcDQgAEtZ6jBN40uRhYnMGHxg2Gs+6E
|
||||
iDcFpl+AZH7EgsTK4a+5j7X8TouC8cvz98OhL0khFPLeRPaLiiFoecT0vXWMLqNT
|
||||
MFEwHQYDVR0OBBYEFGecfGnYqZFVgUApHGgX2kSIhUusMB8GA1UdIwQYMBaAFGec
|
||||
fGnYqZFVgUApHGgX2kSIhUusMA8GA1UdEwEB/wQFMAMBAf8wCgYIKoZIzj0EAwID
|
||||
SQAwRgIhAJ3VWO8JZ7FEOJhxpUCeyOgl+G4vXSHtj9J9NRD3uGGZAiEAsTKGLOGE
|
||||
9c6CtLDU9Ohf1c+Xj2Yi9H+srLZj1mrsnd4=
|
||||
-----END CERTIFICATE-----
|
||||
`
|
||||
)
|
||||
|
||||
func TestOpensslCert(t *testing.T) {
|
||||
// Check that CertificateFromPEM can parse certificates with the PRIVATE KEY before the CERTIFICATE block
|
||||
_, err := CertificateFromPEM(certHeader + certPriv + certCert)
|
||||
assert.Nil(t, err)
|
||||
}
|
||||
|
||||
func TestEmpty(t *testing.T) {
|
||||
cert, err := CertificateFromPEM("")
|
||||
assert.Nil(t, cert)
|
||||
assert.Equal(t, errCertificatePEMMissing, err)
|
||||
}
|
||||
|
||||
func TestMultiCert(t *testing.T) {
|
||||
cert, err := CertificateFromPEM(certHeader + certCert + certPriv + certCert)
|
||||
assert.Nil(t, cert)
|
||||
assert.Equal(t, errCertificatePEMMultipleCert, err)
|
||||
}
|
||||
|
||||
func TestMultiPriv(t *testing.T) {
|
||||
cert, err := CertificateFromPEM(certPriv + certHeader + certCert + certPriv)
|
||||
assert.Nil(t, cert)
|
||||
assert.Equal(t, errCertificatePEMMultiplePriv, err)
|
||||
}
|
||||
|
@@ -275,7 +275,9 @@ var (
|
||||
errICETransportNotInNew = errors.New("ICETransport can only be called in ICETransportStateNew")
|
||||
errICETransportClosed = errors.New("ICETransport closed")
|
||||
|
||||
errCertificatePEMFormatError = errors.New("bad Certificate PEM format")
|
||||
errCertificatePEMMultipleCert = errors.New("failed parsing certificate, more than 1 CERTIFICATE block in pems")
|
||||
errCertificatePEMMultiplePriv = errors.New("failed parsing certificate, more than 1 PRIVATE KEY block in pems")
|
||||
errCertificatePEMMissing = errors.New("failed parsing certificate, pems must contain both a CERTIFICATE block and a PRIVATE KEY block") // nolint: lll
|
||||
|
||||
errRTPTooShort = errors.New("not long enough to be a RTP Packet")
|
||||
|
||||
|
Reference in New Issue
Block a user