debian-forge-composer/vendor/github.com/containers/libtrust/rsa_key.go
Christian Kellner 986f076276 container: add support for uploading to registries
Add a new generic container registry client via a new `container`
package. Use this to create a command line utility as well as a
new upload target for container registries.

The code uses the github.com/containers/* project and packages to
interact with container registires that is also used by skopeo,
podman et al. One if the dependencies is `proglottis/gpgme` that
is using cgo to bind libgpgme, so we have to add the corresponding
devel package to the BuildRequires as well as installing it on CI.

Checks will follow later via an integration test.
2022-06-29 10:02:46 +02:00

427 lines
13 KiB
Go

package libtrust
import (
"crypto"
"crypto/rand"
"crypto/rsa"
"crypto/x509"
"encoding/json"
"encoding/pem"
"errors"
"fmt"
"io"
"math/big"
)
/*
* RSA DSA PUBLIC KEY
*/
// rsaPublicKey implements a JWK Public Key using RSA digital signature algorithms.
type rsaPublicKey struct {
*rsa.PublicKey
extended map[string]interface{}
}
func fromRSAPublicKey(cryptoPublicKey *rsa.PublicKey) *rsaPublicKey {
return &rsaPublicKey{cryptoPublicKey, map[string]interface{}{}}
}
// KeyType returns the JWK key type for RSA keys, i.e., "RSA".
func (k *rsaPublicKey) KeyType() string {
return "RSA"
}
// KeyID returns a distinct identifier which is unique to this Public Key.
func (k *rsaPublicKey) KeyID() string {
return keyIDFromCryptoKey(k)
}
func (k *rsaPublicKey) String() string {
return fmt.Sprintf("RSA Public Key <%s>", k.KeyID())
}
// Verify verifyies the signature of the data in the io.Reader using this Public Key.
// The alg parameter should be the name of the JWA digital signature algorithm
// which was used to produce the signature and should be supported by this
// public key. Returns a nil error if the signature is valid.
func (k *rsaPublicKey) Verify(data io.Reader, alg string, signature []byte) error {
// Verify the signature of the given date, return non-nil error if valid.
sigAlg, err := rsaSignatureAlgorithmByName(alg)
if err != nil {
return fmt.Errorf("unable to verify Signature: %s", err)
}
hasher := sigAlg.HashID().New()
_, err = io.Copy(hasher, data)
if err != nil {
return fmt.Errorf("error reading data to sign: %s", err)
}
hash := hasher.Sum(nil)
err = rsa.VerifyPKCS1v15(k.PublicKey, sigAlg.HashID(), hash, signature)
if err != nil {
return fmt.Errorf("invalid %s signature: %s", sigAlg.HeaderParam(), err)
}
return nil
}
// CryptoPublicKey returns the internal object which can be used as a
// crypto.PublicKey for use with other standard library operations. The type
// is either *rsa.PublicKey or *ecdsa.PublicKey
func (k *rsaPublicKey) CryptoPublicKey() crypto.PublicKey {
return k.PublicKey
}
func (k *rsaPublicKey) toMap() map[string]interface{} {
jwk := make(map[string]interface{})
for k, v := range k.extended {
jwk[k] = v
}
jwk["kty"] = k.KeyType()
jwk["kid"] = k.KeyID()
jwk["n"] = joseBase64UrlEncode(k.N.Bytes())
jwk["e"] = joseBase64UrlEncode(serializeRSAPublicExponentParam(k.E))
return jwk
}
// MarshalJSON serializes this Public Key using the JWK JSON serialization format for
// RSA keys.
func (k *rsaPublicKey) MarshalJSON() (data []byte, err error) {
return json.Marshal(k.toMap())
}
// PEMBlock serializes this Public Key to DER-encoded PKIX format.
func (k *rsaPublicKey) PEMBlock() (*pem.Block, error) {
derBytes, err := x509.MarshalPKIXPublicKey(k.PublicKey)
if err != nil {
return nil, fmt.Errorf("unable to serialize RSA PublicKey to DER-encoded PKIX format: %s", err)
}
k.extended["kid"] = k.KeyID() // For display purposes.
return createPemBlock("PUBLIC KEY", derBytes, k.extended)
}
func (k *rsaPublicKey) AddExtendedField(field string, value interface{}) {
k.extended[field] = value
}
func (k *rsaPublicKey) GetExtendedField(field string) interface{} {
v, ok := k.extended[field]
if !ok {
return nil
}
return v
}
func rsaPublicKeyFromMap(jwk map[string]interface{}) (*rsaPublicKey, error) {
// JWK key type (kty) has already been determined to be "RSA".
// Need to extract 'n', 'e', and 'kid' and check for
// consistency.
// Get the modulus parameter N.
nB64Url, err := stringFromMap(jwk, "n")
if err != nil {
return nil, fmt.Errorf("JWK RSA Public Key modulus: %s", err)
}
n, err := parseRSAModulusParam(nB64Url)
if err != nil {
return nil, fmt.Errorf("JWK RSA Public Key modulus: %s", err)
}
// Get the public exponent E.
eB64Url, err := stringFromMap(jwk, "e")
if err != nil {
return nil, fmt.Errorf("JWK RSA Public Key exponent: %s", err)
}
e, err := parseRSAPublicExponentParam(eB64Url)
if err != nil {
return nil, fmt.Errorf("JWK RSA Public Key exponent: %s", err)
}
key := &rsaPublicKey{
PublicKey: &rsa.PublicKey{N: n, E: e},
}
// Key ID is optional, but if it exists, it should match the key.
_, ok := jwk["kid"]
if ok {
kid, err := stringFromMap(jwk, "kid")
if err != nil {
return nil, fmt.Errorf("JWK RSA Public Key ID: %s", err)
}
if kid != key.KeyID() {
return nil, fmt.Errorf("JWK RSA Public Key ID does not match: %s", kid)
}
}
if _, ok := jwk["d"]; ok {
return nil, fmt.Errorf("JWK RSA Public Key cannot contain private exponent")
}
key.extended = jwk
return key, nil
}
/*
* RSA DSA PRIVATE KEY
*/
// rsaPrivateKey implements a JWK Private Key using RSA digital signature algorithms.
type rsaPrivateKey struct {
rsaPublicKey
*rsa.PrivateKey
}
func fromRSAPrivateKey(cryptoPrivateKey *rsa.PrivateKey) *rsaPrivateKey {
return &rsaPrivateKey{
*fromRSAPublicKey(&cryptoPrivateKey.PublicKey),
cryptoPrivateKey,
}
}
// PublicKey returns the Public Key data associated with this Private Key.
func (k *rsaPrivateKey) PublicKey() PublicKey {
return &k.rsaPublicKey
}
func (k *rsaPrivateKey) String() string {
return fmt.Sprintf("RSA Private Key <%s>", k.KeyID())
}
// Sign signs the data read from the io.Reader using a signature algorithm supported
// by the RSA private key. If the specified hashing algorithm is supported by
// this key, that hash function is used to generate the signature otherwise the
// the default hashing algorithm for this key is used. Returns the signature
// and the name of the JWK signature algorithm used, e.g., "RS256", "RS384",
// "RS512".
func (k *rsaPrivateKey) Sign(data io.Reader, hashID crypto.Hash) (signature []byte, alg string, err error) {
// Generate a signature of the data using the internal alg.
sigAlg := rsaPKCS1v15SignatureAlgorithmForHashID(hashID)
hasher := sigAlg.HashID().New()
_, err = io.Copy(hasher, data)
if err != nil {
return nil, "", fmt.Errorf("error reading data to sign: %s", err)
}
hash := hasher.Sum(nil)
signature, err = rsa.SignPKCS1v15(rand.Reader, k.PrivateKey, sigAlg.HashID(), hash)
if err != nil {
return nil, "", fmt.Errorf("error producing signature: %s", err)
}
alg = sigAlg.HeaderParam()
return
}
// CryptoPrivateKey returns the internal object which can be used as a
// crypto.PublicKey for use with other standard library operations. The type
// is either *rsa.PublicKey or *ecdsa.PublicKey
func (k *rsaPrivateKey) CryptoPrivateKey() crypto.PrivateKey {
return k.PrivateKey
}
func (k *rsaPrivateKey) toMap() map[string]interface{} {
k.Precompute() // Make sure the precomputed values are stored.
jwk := k.rsaPublicKey.toMap()
jwk["d"] = joseBase64UrlEncode(k.D.Bytes())
jwk["p"] = joseBase64UrlEncode(k.Primes[0].Bytes())
jwk["q"] = joseBase64UrlEncode(k.Primes[1].Bytes())
jwk["dp"] = joseBase64UrlEncode(k.Precomputed.Dp.Bytes())
jwk["dq"] = joseBase64UrlEncode(k.Precomputed.Dq.Bytes())
jwk["qi"] = joseBase64UrlEncode(k.Precomputed.Qinv.Bytes())
otherPrimes := k.Primes[2:]
if len(otherPrimes) > 0 {
otherPrimesInfo := make([]interface{}, len(otherPrimes))
for i, r := range otherPrimes {
otherPrimeInfo := make(map[string]string, 3)
otherPrimeInfo["r"] = joseBase64UrlEncode(r.Bytes())
crtVal := k.Precomputed.CRTValues[i]
otherPrimeInfo["d"] = joseBase64UrlEncode(crtVal.Exp.Bytes())
otherPrimeInfo["t"] = joseBase64UrlEncode(crtVal.Coeff.Bytes())
otherPrimesInfo[i] = otherPrimeInfo
}
jwk["oth"] = otherPrimesInfo
}
return jwk
}
// MarshalJSON serializes this Private Key using the JWK JSON serialization format for
// RSA keys.
func (k *rsaPrivateKey) MarshalJSON() (data []byte, err error) {
return json.Marshal(k.toMap())
}
// PEMBlock serializes this Private Key to DER-encoded PKIX format.
func (k *rsaPrivateKey) PEMBlock() (*pem.Block, error) {
derBytes := x509.MarshalPKCS1PrivateKey(k.PrivateKey)
k.extended["keyID"] = k.KeyID() // For display purposes.
return createPemBlock("RSA PRIVATE KEY", derBytes, k.extended)
}
func rsaPrivateKeyFromMap(jwk map[string]interface{}) (*rsaPrivateKey, error) {
// The JWA spec for RSA Private Keys (draft rfc section 5.3.2) states that
// only the private key exponent 'd' is REQUIRED, the others are just for
// signature/decryption optimizations and SHOULD be included when the JWK
// is produced. We MAY choose to accept a JWK which only includes 'd', but
// we're going to go ahead and not choose to accept it without the extra
// fields. Only the 'oth' field will be optional (for multi-prime keys).
privateExponent, err := parseRSAPrivateKeyParamFromMap(jwk, "d")
if err != nil {
return nil, fmt.Errorf("JWK RSA Private Key exponent: %s", err)
}
firstPrimeFactor, err := parseRSAPrivateKeyParamFromMap(jwk, "p")
if err != nil {
return nil, fmt.Errorf("JWK RSA Private Key prime factor: %s", err)
}
secondPrimeFactor, err := parseRSAPrivateKeyParamFromMap(jwk, "q")
if err != nil {
return nil, fmt.Errorf("JWK RSA Private Key prime factor: %s", err)
}
firstFactorCRT, err := parseRSAPrivateKeyParamFromMap(jwk, "dp")
if err != nil {
return nil, fmt.Errorf("JWK RSA Private Key CRT exponent: %s", err)
}
secondFactorCRT, err := parseRSAPrivateKeyParamFromMap(jwk, "dq")
if err != nil {
return nil, fmt.Errorf("JWK RSA Private Key CRT exponent: %s", err)
}
crtCoeff, err := parseRSAPrivateKeyParamFromMap(jwk, "qi")
if err != nil {
return nil, fmt.Errorf("JWK RSA Private Key CRT coefficient: %s", err)
}
var oth interface{}
if _, ok := jwk["oth"]; ok {
oth = jwk["oth"]
delete(jwk, "oth")
}
// JWK key type (kty) has already been determined to be "RSA".
// Need to extract the public key information, then extract the private
// key values.
publicKey, err := rsaPublicKeyFromMap(jwk)
if err != nil {
return nil, err
}
privateKey := &rsa.PrivateKey{
PublicKey: *publicKey.PublicKey,
D: privateExponent,
Primes: []*big.Int{firstPrimeFactor, secondPrimeFactor},
Precomputed: rsa.PrecomputedValues{
Dp: firstFactorCRT,
Dq: secondFactorCRT,
Qinv: crtCoeff,
},
}
if oth != nil {
// Should be an array of more JSON objects.
otherPrimesInfo, ok := oth.([]interface{})
if !ok {
return nil, errors.New("JWK RSA Private Key: Invalid other primes info: must be an array")
}
numOtherPrimeFactors := len(otherPrimesInfo)
if numOtherPrimeFactors == 0 {
return nil, errors.New("JWK RSA Privake Key: Invalid other primes info: must be absent or non-empty")
}
otherPrimeFactors := make([]*big.Int, numOtherPrimeFactors)
productOfPrimes := new(big.Int).Mul(firstPrimeFactor, secondPrimeFactor)
crtValues := make([]rsa.CRTValue, numOtherPrimeFactors)
for i, val := range otherPrimesInfo {
otherPrimeinfo, ok := val.(map[string]interface{})
if !ok {
return nil, errors.New("JWK RSA Private Key: Invalid other prime info: must be a JSON object")
}
otherPrimeFactor, err := parseRSAPrivateKeyParamFromMap(otherPrimeinfo, "r")
if err != nil {
return nil, fmt.Errorf("JWK RSA Private Key prime factor: %s", err)
}
otherFactorCRT, err := parseRSAPrivateKeyParamFromMap(otherPrimeinfo, "d")
if err != nil {
return nil, fmt.Errorf("JWK RSA Private Key CRT exponent: %s", err)
}
otherCrtCoeff, err := parseRSAPrivateKeyParamFromMap(otherPrimeinfo, "t")
if err != nil {
return nil, fmt.Errorf("JWK RSA Private Key CRT coefficient: %s", err)
}
crtValue := crtValues[i]
crtValue.Exp = otherFactorCRT
crtValue.Coeff = otherCrtCoeff
crtValue.R = productOfPrimes
otherPrimeFactors[i] = otherPrimeFactor
productOfPrimes = new(big.Int).Mul(productOfPrimes, otherPrimeFactor)
}
privateKey.Primes = append(privateKey.Primes, otherPrimeFactors...)
privateKey.Precomputed.CRTValues = crtValues
}
key := &rsaPrivateKey{
rsaPublicKey: *publicKey,
PrivateKey: privateKey,
}
return key, nil
}
/*
* Key Generation Functions.
*/
func generateRSAPrivateKey(bits int) (k *rsaPrivateKey, err error) {
k = new(rsaPrivateKey)
k.PrivateKey, err = rsa.GenerateKey(rand.Reader, bits)
if err != nil {
return nil, err
}
k.rsaPublicKey.PublicKey = &k.PrivateKey.PublicKey
k.extended = make(map[string]interface{})
return
}
// GenerateRSA2048PrivateKey generates a key pair using 2048-bit RSA.
func GenerateRSA2048PrivateKey() (PrivateKey, error) {
k, err := generateRSAPrivateKey(2048)
if err != nil {
return nil, fmt.Errorf("error generating RSA 2048-bit key: %s", err)
}
return k, nil
}
// GenerateRSA3072PrivateKey generates a key pair using 3072-bit RSA.
func GenerateRSA3072PrivateKey() (PrivateKey, error) {
k, err := generateRSAPrivateKey(3072)
if err != nil {
return nil, fmt.Errorf("error generating RSA 3072-bit key: %s", err)
}
return k, nil
}
// GenerateRSA4096PrivateKey generates a key pair using 4096-bit RSA.
func GenerateRSA4096PrivateKey() (PrivateKey, error) {
k, err := generateRSAPrivateKey(4096)
if err != nil {
return nil, fmt.Errorf("error generating RSA 4096-bit key: %s", err)
}
return k, nil
}