dubbo.apache.org/dubbo-go/v3@v3.1.1/xds/credentials/certgenerate/crypto.go (about)

     1  /*
     2   * Licensed to the Apache Software Foundation (ASF) under one or more
     3   * contributor license agreements.  See the NOTICE file distributed with
     4   * this work for additional information regarding copyright ownership.
     5   * The ASF licenses this file to You under the Apache License, Version 2.0
     6   * (the "License"); you may not use this file except in compliance with
     7   * the License.  You may obtain a copy of the License at
     8   *
     9   *     http://www.apache.org/licenses/LICENSE-2.0
    10   *
    11   * Unless required by applicable law or agreed to in writing, software
    12   * distributed under the License is distributed on an "AS IS" BASIS,
    13   * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
    14   * See the License for the specific language governing permissions and
    15   * limitations under the License.
    16   */
    17  
    18  /*
    19   *
    20   * Copyright Istio Authors
    21   *
    22   */
    23  
    24  package certgenerate
    25  
    26  import (
    27  	"crypto"
    28  	"crypto/ecdsa"
    29  	"crypto/rsa"
    30  	"crypto/x509"
    31  	"encoding/pem"
    32  	"fmt"
    33  	"reflect"
    34  	"strings"
    35  )
    36  
    37  const (
    38  	blockTypeECPrivateKey    = "EC PRIVATE KEY"
    39  	blockTypeRSAPrivateKey   = "RSA PRIVATE KEY" // PKCS#1 private key
    40  	blockTypePKCS8PrivateKey = "PRIVATE KEY"     // PKCS#8 plain private key
    41  )
    42  
    43  // ParsePemEncodedCertificate constructs a `x509.Certificate` object using the
    44  // given a PEM-encoded certificate.
    45  func ParsePemEncodedCertificate(certBytes []byte) (*x509.Certificate, error) {
    46  	cb, _ := pem.Decode(certBytes)
    47  	if cb == nil {
    48  		return nil, fmt.Errorf("invalid PEM encoded certificate")
    49  	}
    50  
    51  	cert, err := x509.ParseCertificate(cb.Bytes)
    52  	if err != nil {
    53  		return nil, fmt.Errorf("failed to parse X.509 certificate")
    54  	}
    55  
    56  	return cert, nil
    57  }
    58  
    59  // ParsePemEncodedCertificateChain constructs a slice of `x509.Certificate`
    60  // objects using the given a PEM-encoded certificate chain.
    61  func ParsePemEncodedCertificateChain(certBytes []byte) ([]*x509.Certificate, error) {
    62  	var (
    63  		certs []*x509.Certificate
    64  		cb    *pem.Block
    65  	)
    66  	for {
    67  		cb, certBytes = pem.Decode(certBytes)
    68  		if cb == nil {
    69  			break
    70  		}
    71  		cert, err := x509.ParseCertificate(cb.Bytes)
    72  		if err != nil {
    73  			return nil, fmt.Errorf("failed to parse X.509 certificate")
    74  		}
    75  		certs = append(certs, cert)
    76  	}
    77  	if len(certs) == 0 {
    78  		return nil, fmt.Errorf("no PEM encoded X.509 certificates parsed")
    79  	}
    80  	return certs, nil
    81  }
    82  
    83  // ParsePemEncodedCSR constructs a `x509.CertificateRequest` object using the
    84  // given PEM-encoded certificate signing request.
    85  func ParsePemEncodedCSR(csrBytes []byte) (*x509.CertificateRequest, error) {
    86  	block, _ := pem.Decode(csrBytes)
    87  	if block == nil {
    88  		return nil, fmt.Errorf("certificate signing request is not properly encoded")
    89  	}
    90  	csr, err := x509.ParseCertificateRequest(block.Bytes)
    91  	if err != nil {
    92  		return nil, fmt.Errorf("failed to parse X.509 certificate signing request")
    93  	}
    94  	return csr, nil
    95  }
    96  
    97  // ParsePemEncodedKey takes a PEM-encoded key and parsed the bytes into a `crypto.PrivateKey`.
    98  func ParsePemEncodedKey(keyBytes []byte) (crypto.PrivateKey, error) {
    99  	kb, _ := pem.Decode(keyBytes)
   100  	if kb == nil {
   101  		return nil, fmt.Errorf("invalid PEM-encoded key")
   102  	}
   103  
   104  	switch kb.Type {
   105  	case blockTypeECPrivateKey:
   106  		key, err := x509.ParseECPrivateKey(kb.Bytes)
   107  		if err != nil {
   108  			return nil, fmt.Errorf("failed to parse the ECDSA private key")
   109  		}
   110  		return key, nil
   111  	case blockTypeRSAPrivateKey:
   112  		key, err := x509.ParsePKCS1PrivateKey(kb.Bytes)
   113  		if err != nil {
   114  			return nil, fmt.Errorf("failed to parse the RSA private key")
   115  		}
   116  		return key, nil
   117  	case blockTypePKCS8PrivateKey:
   118  		key, err := x509.ParsePKCS8PrivateKey(kb.Bytes)
   119  		if err != nil {
   120  			return nil, fmt.Errorf("failed to parse the PKCS8 private key")
   121  		}
   122  		return key, nil
   123  	default:
   124  		return nil, fmt.Errorf("unsupported PEM block type for a private key: %s", kb.Type)
   125  	}
   126  }
   127  
   128  // GetRSAKeySize returns the size if it is RSA key, otherwise it returns an error.
   129  func GetRSAKeySize(privKey crypto.PrivateKey) (int, error) {
   130  	if t := reflect.TypeOf(privKey); t != reflect.TypeOf(&rsa.PrivateKey{}) {
   131  		return 0, fmt.Errorf("key type is not RSA: %v", t)
   132  	}
   133  	pkey := privKey.(*rsa.PrivateKey)
   134  	return pkey.N.BitLen(), nil
   135  }
   136  
   137  // IsSupportedECPrivateKey is a predicate returning true if the private key is EC based
   138  func IsSupportedECPrivateKey(privKey *crypto.PrivateKey) bool {
   139  	switch (*privKey).(type) {
   140  	// this should agree with var SupportedECSignatureAlgorithms
   141  	case *ecdsa.PrivateKey:
   142  		return true
   143  	default:
   144  		return false
   145  	}
   146  }
   147  
   148  // PemCertBytestoString: takes an array of PEM certs in bytes and returns a string array in the same order with
   149  // trailing newline characters removed
   150  func PemCertBytestoString(caCerts []byte) []string {
   151  	certs := []string{}
   152  	var cert string
   153  	pemBlock := caCerts
   154  	for block, rest := pem.Decode(pemBlock); block != nil && len(block.Bytes) != 0; block, rest = pem.Decode(pemBlock) {
   155  		if len(rest) == 0 {
   156  			cert = strings.TrimPrefix(strings.TrimSuffix(string(pemBlock), "\n"), "\n")
   157  			certs = append(certs, cert)
   158  			break
   159  		}
   160  		cert = string(pemBlock[0 : len(pemBlock)-len(rest)])
   161  		cert = strings.TrimPrefix(strings.TrimSuffix(cert, "\n"), "\n")
   162  		certs = append(certs, cert)
   163  		pemBlock = rest
   164  	}
   165  	return certs
   166  }