mirror of
				https://gitea.com/Lydanne/buildx.git
				synced 2025-10-31 16:13:45 +08:00 
			
		
		
		
	
		
			
				
	
	
		
			270 lines
		
	
	
		
			7.7 KiB
		
	
	
	
		
			Go
		
	
	
	
	
	
			
		
		
	
	
			270 lines
		
	
	
		
			7.7 KiB
		
	
	
	
		
			Go
		
	
	
	
	
	
| /*
 | |
| Copyright 2014 The Kubernetes Authors.
 | |
| 
 | |
| Licensed under the Apache License, Version 2.0 (the "License");
 | |
| you may not use this file except in compliance with the License.
 | |
| You may obtain a copy of the License at
 | |
| 
 | |
|     http://www.apache.org/licenses/LICENSE-2.0
 | |
| 
 | |
| Unless required by applicable law or agreed to in writing, software
 | |
| distributed under the License is distributed on an "AS IS" BASIS,
 | |
| WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
 | |
| See the License for the specific language governing permissions and
 | |
| limitations under the License.
 | |
| */
 | |
| 
 | |
| package cert
 | |
| 
 | |
| import (
 | |
| 	"crypto/ecdsa"
 | |
| 	"crypto/rsa"
 | |
| 	"crypto/x509"
 | |
| 	"encoding/pem"
 | |
| 	"errors"
 | |
| 	"fmt"
 | |
| )
 | |
| 
 | |
| const (
 | |
| 	// ECPrivateKeyBlockType is a possible value for pem.Block.Type.
 | |
| 	ECPrivateKeyBlockType = "EC PRIVATE KEY"
 | |
| 	// RSAPrivateKeyBlockType is a possible value for pem.Block.Type.
 | |
| 	RSAPrivateKeyBlockType = "RSA PRIVATE KEY"
 | |
| 	// PrivateKeyBlockType is a possible value for pem.Block.Type.
 | |
| 	PrivateKeyBlockType = "PRIVATE KEY"
 | |
| 	// PublicKeyBlockType is a possible value for pem.Block.Type.
 | |
| 	PublicKeyBlockType = "PUBLIC KEY"
 | |
| 	// CertificateBlockType is a possible value for pem.Block.Type.
 | |
| 	CertificateBlockType = "CERTIFICATE"
 | |
| 	// CertificateRequestBlockType is a possible value for pem.Block.Type.
 | |
| 	CertificateRequestBlockType = "CERTIFICATE REQUEST"
 | |
| )
 | |
| 
 | |
| // EncodePublicKeyPEM returns PEM-encoded public data
 | |
| func EncodePublicKeyPEM(key *rsa.PublicKey) ([]byte, error) {
 | |
| 	der, err := x509.MarshalPKIXPublicKey(key)
 | |
| 	if err != nil {
 | |
| 		return []byte{}, err
 | |
| 	}
 | |
| 	block := pem.Block{
 | |
| 		Type:  PublicKeyBlockType,
 | |
| 		Bytes: der,
 | |
| 	}
 | |
| 	return pem.EncodeToMemory(&block), nil
 | |
| }
 | |
| 
 | |
| // EncodePrivateKeyPEM returns PEM-encoded private key data
 | |
| func EncodePrivateKeyPEM(key *rsa.PrivateKey) []byte {
 | |
| 	block := pem.Block{
 | |
| 		Type:  RSAPrivateKeyBlockType,
 | |
| 		Bytes: x509.MarshalPKCS1PrivateKey(key),
 | |
| 	}
 | |
| 	return pem.EncodeToMemory(&block)
 | |
| }
 | |
| 
 | |
| // EncodeCertPEM returns PEM-endcoded certificate data
 | |
| func EncodeCertPEM(cert *x509.Certificate) []byte {
 | |
| 	block := pem.Block{
 | |
| 		Type:  CertificateBlockType,
 | |
| 		Bytes: cert.Raw,
 | |
| 	}
 | |
| 	return pem.EncodeToMemory(&block)
 | |
| }
 | |
| 
 | |
| // ParsePrivateKeyPEM returns a private key parsed from a PEM block in the supplied data.
 | |
| // Recognizes PEM blocks for "EC PRIVATE KEY", "RSA PRIVATE KEY", or "PRIVATE KEY"
 | |
| func ParsePrivateKeyPEM(keyData []byte) (interface{}, error) {
 | |
| 	var privateKeyPemBlock *pem.Block
 | |
| 	for {
 | |
| 		privateKeyPemBlock, keyData = pem.Decode(keyData)
 | |
| 		if privateKeyPemBlock == nil {
 | |
| 			break
 | |
| 		}
 | |
| 
 | |
| 		switch privateKeyPemBlock.Type {
 | |
| 		case ECPrivateKeyBlockType:
 | |
| 			// ECDSA Private Key in ASN.1 format
 | |
| 			if key, err := x509.ParseECPrivateKey(privateKeyPemBlock.Bytes); err == nil {
 | |
| 				return key, nil
 | |
| 			}
 | |
| 		case RSAPrivateKeyBlockType:
 | |
| 			// RSA Private Key in PKCS#1 format
 | |
| 			if key, err := x509.ParsePKCS1PrivateKey(privateKeyPemBlock.Bytes); err == nil {
 | |
| 				return key, nil
 | |
| 			}
 | |
| 		case PrivateKeyBlockType:
 | |
| 			// RSA or ECDSA Private Key in unencrypted PKCS#8 format
 | |
| 			if key, err := x509.ParsePKCS8PrivateKey(privateKeyPemBlock.Bytes); err == nil {
 | |
| 				return key, nil
 | |
| 			}
 | |
| 		}
 | |
| 
 | |
| 		// tolerate non-key PEM blocks for compatibility with things like "EC PARAMETERS" blocks
 | |
| 		// originally, only the first PEM block was parsed and expected to be a key block
 | |
| 	}
 | |
| 
 | |
| 	// we read all the PEM blocks and didn't recognize one
 | |
| 	return nil, fmt.Errorf("data does not contain a valid RSA or ECDSA private key")
 | |
| }
 | |
| 
 | |
| // ParsePublicKeysPEM is a helper function for reading an array of rsa.PublicKey or ecdsa.PublicKey from a PEM-encoded byte array.
 | |
| // Reads public keys from both public and private key files.
 | |
| func ParsePublicKeysPEM(keyData []byte) ([]interface{}, error) {
 | |
| 	var block *pem.Block
 | |
| 	keys := []interface{}{}
 | |
| 	for {
 | |
| 		// read the next block
 | |
| 		block, keyData = pem.Decode(keyData)
 | |
| 		if block == nil {
 | |
| 			break
 | |
| 		}
 | |
| 
 | |
| 		// test block against parsing functions
 | |
| 		if privateKey, err := parseRSAPrivateKey(block.Bytes); err == nil {
 | |
| 			keys = append(keys, &privateKey.PublicKey)
 | |
| 			continue
 | |
| 		}
 | |
| 		if publicKey, err := parseRSAPublicKey(block.Bytes); err == nil {
 | |
| 			keys = append(keys, publicKey)
 | |
| 			continue
 | |
| 		}
 | |
| 		if privateKey, err := parseECPrivateKey(block.Bytes); err == nil {
 | |
| 			keys = append(keys, &privateKey.PublicKey)
 | |
| 			continue
 | |
| 		}
 | |
| 		if publicKey, err := parseECPublicKey(block.Bytes); err == nil {
 | |
| 			keys = append(keys, publicKey)
 | |
| 			continue
 | |
| 		}
 | |
| 
 | |
| 		// tolerate non-key PEM blocks for backwards compatibility
 | |
| 		// originally, only the first PEM block was parsed and expected to be a key block
 | |
| 	}
 | |
| 
 | |
| 	if len(keys) == 0 {
 | |
| 		return nil, fmt.Errorf("data does not contain any valid RSA or ECDSA public keys")
 | |
| 	}
 | |
| 	return keys, nil
 | |
| }
 | |
| 
 | |
| // ParseCertsPEM returns the x509.Certificates contained in the given PEM-encoded byte array
 | |
| // Returns an error if a certificate could not be parsed, or if the data does not contain any certificates
 | |
| func ParseCertsPEM(pemCerts []byte) ([]*x509.Certificate, error) {
 | |
| 	ok := false
 | |
| 	certs := []*x509.Certificate{}
 | |
| 	for len(pemCerts) > 0 {
 | |
| 		var block *pem.Block
 | |
| 		block, pemCerts = pem.Decode(pemCerts)
 | |
| 		if block == nil {
 | |
| 			break
 | |
| 		}
 | |
| 		// Only use PEM "CERTIFICATE" blocks without extra headers
 | |
| 		if block.Type != CertificateBlockType || len(block.Headers) != 0 {
 | |
| 			continue
 | |
| 		}
 | |
| 
 | |
| 		cert, err := x509.ParseCertificate(block.Bytes)
 | |
| 		if err != nil {
 | |
| 			return certs, err
 | |
| 		}
 | |
| 
 | |
| 		certs = append(certs, cert)
 | |
| 		ok = true
 | |
| 	}
 | |
| 
 | |
| 	if !ok {
 | |
| 		return certs, errors.New("data does not contain any valid RSA or ECDSA certificates")
 | |
| 	}
 | |
| 	return certs, nil
 | |
| }
 | |
| 
 | |
| // parseRSAPublicKey parses a single RSA public key from the provided data
 | |
| func parseRSAPublicKey(data []byte) (*rsa.PublicKey, error) {
 | |
| 	var err error
 | |
| 
 | |
| 	// Parse the key
 | |
| 	var parsedKey interface{}
 | |
| 	if parsedKey, err = x509.ParsePKIXPublicKey(data); err != nil {
 | |
| 		if cert, err := x509.ParseCertificate(data); err == nil {
 | |
| 			parsedKey = cert.PublicKey
 | |
| 		} else {
 | |
| 			return nil, err
 | |
| 		}
 | |
| 	}
 | |
| 
 | |
| 	// Test if parsed key is an RSA Public Key
 | |
| 	var pubKey *rsa.PublicKey
 | |
| 	var ok bool
 | |
| 	if pubKey, ok = parsedKey.(*rsa.PublicKey); !ok {
 | |
| 		return nil, fmt.Errorf("data doesn't contain valid RSA Public Key")
 | |
| 	}
 | |
| 
 | |
| 	return pubKey, nil
 | |
| }
 | |
| 
 | |
| // parseRSAPrivateKey parses a single RSA private key from the provided data
 | |
| func parseRSAPrivateKey(data []byte) (*rsa.PrivateKey, error) {
 | |
| 	var err error
 | |
| 
 | |
| 	// Parse the key
 | |
| 	var parsedKey interface{}
 | |
| 	if parsedKey, err = x509.ParsePKCS1PrivateKey(data); err != nil {
 | |
| 		if parsedKey, err = x509.ParsePKCS8PrivateKey(data); err != nil {
 | |
| 			return nil, err
 | |
| 		}
 | |
| 	}
 | |
| 
 | |
| 	// Test if parsed key is an RSA Private Key
 | |
| 	var privKey *rsa.PrivateKey
 | |
| 	var ok bool
 | |
| 	if privKey, ok = parsedKey.(*rsa.PrivateKey); !ok {
 | |
| 		return nil, fmt.Errorf("data doesn't contain valid RSA Private Key")
 | |
| 	}
 | |
| 
 | |
| 	return privKey, nil
 | |
| }
 | |
| 
 | |
| // parseECPublicKey parses a single ECDSA public key from the provided data
 | |
| func parseECPublicKey(data []byte) (*ecdsa.PublicKey, error) {
 | |
| 	var err error
 | |
| 
 | |
| 	// Parse the key
 | |
| 	var parsedKey interface{}
 | |
| 	if parsedKey, err = x509.ParsePKIXPublicKey(data); err != nil {
 | |
| 		if cert, err := x509.ParseCertificate(data); err == nil {
 | |
| 			parsedKey = cert.PublicKey
 | |
| 		} else {
 | |
| 			return nil, err
 | |
| 		}
 | |
| 	}
 | |
| 
 | |
| 	// Test if parsed key is an ECDSA Public Key
 | |
| 	var pubKey *ecdsa.PublicKey
 | |
| 	var ok bool
 | |
| 	if pubKey, ok = parsedKey.(*ecdsa.PublicKey); !ok {
 | |
| 		return nil, fmt.Errorf("data doesn't contain valid ECDSA Public Key")
 | |
| 	}
 | |
| 
 | |
| 	return pubKey, nil
 | |
| }
 | |
| 
 | |
| // parseECPrivateKey parses a single ECDSA private key from the provided data
 | |
| func parseECPrivateKey(data []byte) (*ecdsa.PrivateKey, error) {
 | |
| 	var err error
 | |
| 
 | |
| 	// Parse the key
 | |
| 	var parsedKey interface{}
 | |
| 	if parsedKey, err = x509.ParseECPrivateKey(data); err != nil {
 | |
| 		return nil, err
 | |
| 	}
 | |
| 
 | |
| 	// Test if parsed key is an ECDSA Private Key
 | |
| 	var privKey *ecdsa.PrivateKey
 | |
| 	var ok bool
 | |
| 	if privKey, ok = parsedKey.(*ecdsa.PrivateKey); !ok {
 | |
| 		return nil, fmt.Errorf("data doesn't contain valid ECDSA Private Key")
 | |
| 	}
 | |
| 
 | |
| 	return privKey, nil
 | |
| }
 | 
