1
0
mirror of https://github.com/containers/skopeo.git synced 2025-05-03 13:36:59 +00:00
skopeo/vendor/github.com/containers/ocicrypt/helpers/parse_helpers.go
tomsweeneyredhat 6f290ebe64 [release-1.9] remove square/jose, and bump to ocicrypt v1.1.8
Remove the dependency for vendor/gopkg.in/square/go-jose.v2 which
ensures that we address cve-2024-28180

Signed-off-by: tomsweeneyredhat <tsweeney@redhat.com>
2024-05-02 16:59:30 -04:00

378 lines
11 KiB
Go

package helpers
import (
"errors"
"fmt"
"os"
"strconv"
"strings"
"github.com/containers/ocicrypt"
encconfig "github.com/containers/ocicrypt/config"
"github.com/containers/ocicrypt/config/pkcs11config"
"github.com/containers/ocicrypt/crypto/pkcs11"
encutils "github.com/containers/ocicrypt/utils"
)
// processRecipientKeys sorts the array of recipients by type. Recipients may be either
// x509 certificates, public keys, or PGP public keys identified by email address or name
func processRecipientKeys(recipients []string) ([][]byte, [][]byte, [][]byte, [][]byte, [][]byte, [][]byte, error) {
var (
gpgRecipients [][]byte
pubkeys [][]byte
x509s [][]byte
pkcs11Pubkeys [][]byte
pkcs11Yamls [][]byte
keyProviders [][]byte
)
for _, recipient := range recipients {
idx := strings.Index(recipient, ":")
if idx < 0 {
return nil, nil, nil, nil, nil, nil, errors.New("Invalid recipient format")
}
protocol := recipient[:idx]
value := recipient[idx+1:]
switch protocol {
case "pgp":
gpgRecipients = append(gpgRecipients, []byte(value))
case "jwe":
tmp, err := os.ReadFile(value)
if err != nil {
return nil, nil, nil, nil, nil, nil, fmt.Errorf("Unable to read file: %w", err)
}
if !encutils.IsPublicKey(tmp) {
return nil, nil, nil, nil, nil, nil, errors.New("File provided is not a public key")
}
pubkeys = append(pubkeys, tmp)
case "pkcs7":
tmp, err := os.ReadFile(value)
if err != nil {
return nil, nil, nil, nil, nil, nil, fmt.Errorf("Unable to read file: %w", err)
}
if !encutils.IsCertificate(tmp) {
return nil, nil, nil, nil, nil, nil, errors.New("File provided is not an x509 cert")
}
x509s = append(x509s, tmp)
case "pkcs11":
tmp, err := os.ReadFile(value)
if err != nil {
return nil, nil, nil, nil, nil, nil, fmt.Errorf("Unable to read file: %w", err)
}
if encutils.IsPkcs11PublicKey(tmp) {
pkcs11Yamls = append(pkcs11Yamls, tmp)
} else if encutils.IsPublicKey(tmp) {
pkcs11Pubkeys = append(pkcs11Pubkeys, tmp)
} else {
return nil, nil, nil, nil, nil, nil, errors.New("Provided file is not a public key")
}
case "provider":
keyProviders = append(keyProviders, []byte(value))
default:
return nil, nil, nil, nil, nil, nil, errors.New("Provided protocol not recognized")
}
}
return gpgRecipients, pubkeys, x509s, pkcs11Pubkeys, pkcs11Yamls, keyProviders, nil
}
// processx509Certs processes x509 certificate files
func processx509Certs(keys []string) ([][]byte, error) {
var x509s [][]byte
for _, key := range keys {
fileName := strings.Split(key, ":")[0]
if _, err := os.Stat(fileName); os.IsNotExist(err) {
continue
}
tmp, err := os.ReadFile(fileName)
if err != nil {
return nil, fmt.Errorf("Unable to read file: %w", err)
}
if !encutils.IsCertificate(tmp) {
continue
}
x509s = append(x509s, tmp)
}
return x509s, nil
}
// processPwdString process a password that may be in any of the following formats:
// - file=<passwordfile>
// - pass=<password>
// - fd=<filedescriptor>
// - <password>
func processPwdString(pwdString string) ([]byte, error) {
if strings.HasPrefix(pwdString, "file=") {
return os.ReadFile(pwdString[5:])
} else if strings.HasPrefix(pwdString, "pass=") {
return []byte(pwdString[5:]), nil
} else if strings.HasPrefix(pwdString, "fd=") {
fdStr := pwdString[3:]
fd, err := strconv.Atoi(fdStr)
if err != nil {
return nil, fmt.Errorf("could not parse file descriptor %s: %w", fdStr, err)
}
f := os.NewFile(uintptr(fd), "pwdfile")
if f == nil {
return nil, fmt.Errorf("%s is not a valid file descriptor", fdStr)
}
defer f.Close()
pwd := make([]byte, 64)
n, err := f.Read(pwd)
if err != nil {
return nil, fmt.Errorf("could not read from file descriptor: %w", err)
}
return pwd[:n], nil
}
return []byte(pwdString), nil
}
// processPrivateKeyFiles sorts the different types of private key files; private key files may either be
// private keys or GPG private key ring files. The private key files may include the password for the
// private key and take any of the following forms:
// - <filename>
// - <filename>:file=<passwordfile>
// - <filename>:pass=<password>
// - <filename>:fd=<filedescriptor>
// - <filename>:<password>
// - keyprovider:<...>
func processPrivateKeyFiles(keyFilesAndPwds []string) ([][]byte, [][]byte, [][]byte, [][]byte, [][]byte, [][]byte, error) {
var (
gpgSecretKeyRingFiles [][]byte
gpgSecretKeyPasswords [][]byte
privkeys [][]byte
privkeysPasswords [][]byte
pkcs11Yamls [][]byte
keyProviders [][]byte
err error
)
// keys needed for decryption in case of adding a recipient
for _, keyfileAndPwd := range keyFilesAndPwds {
var password []byte
// treat "provider" protocol separately
if strings.HasPrefix(keyfileAndPwd, "provider:") {
keyProviders = append(keyProviders, []byte(keyfileAndPwd[len("provider:"):]))
continue
}
parts := strings.Split(keyfileAndPwd, ":")
if len(parts) == 2 {
password, err = processPwdString(parts[1])
if err != nil {
return nil, nil, nil, nil, nil, nil, err
}
}
keyfile := parts[0]
tmp, err := os.ReadFile(keyfile)
if err != nil {
return nil, nil, nil, nil, nil, nil, err
}
isPrivKey, err := encutils.IsPrivateKey(tmp, password)
if encutils.IsPasswordError(err) {
return nil, nil, nil, nil, nil, nil, err
}
if encutils.IsPkcs11PrivateKey(tmp) {
pkcs11Yamls = append(pkcs11Yamls, tmp)
} else if isPrivKey {
privkeys = append(privkeys, tmp)
privkeysPasswords = append(privkeysPasswords, password)
} else if encutils.IsGPGPrivateKeyRing(tmp) {
gpgSecretKeyRingFiles = append(gpgSecretKeyRingFiles, tmp)
gpgSecretKeyPasswords = append(gpgSecretKeyPasswords, password)
} else {
// ignore if file is not recognized, so as not to error if additional
// metadata/cert files exists
continue
}
}
return gpgSecretKeyRingFiles, gpgSecretKeyPasswords, privkeys, privkeysPasswords, pkcs11Yamls, keyProviders, nil
}
// CreateDecryptCryptoConfig creates the CryptoConfig object that contains the necessary
// information to perform decryption from command line options.
func CreateDecryptCryptoConfig(keys []string, decRecipients []string) (encconfig.CryptoConfig, error) {
ccs := []encconfig.CryptoConfig{}
// x509 cert is needed for PKCS7 decryption
_, _, x509s, _, _, _, err := processRecipientKeys(decRecipients)
if err != nil {
return encconfig.CryptoConfig{}, err
}
// x509 certs can also be passed in via keys
x509FromKeys, err := processx509Certs(keys)
if err != nil {
return encconfig.CryptoConfig{}, err
}
x509s = append(x509s, x509FromKeys...)
gpgSecretKeyRingFiles, gpgSecretKeyPasswords, privKeys, privKeysPasswords, pkcs11Yamls, keyProviders, err := processPrivateKeyFiles(keys)
if err != nil {
return encconfig.CryptoConfig{}, err
}
if len(gpgSecretKeyRingFiles) > 0 {
gpgCc, err := encconfig.DecryptWithGpgPrivKeys(gpgSecretKeyRingFiles, gpgSecretKeyPasswords)
if err != nil {
return encconfig.CryptoConfig{}, err
}
ccs = append(ccs, gpgCc)
}
/* TODO: Add in GPG client query for secret keys in the future.
_, err = createGPGClient(context)
gpgInstalled := err == nil
if gpgInstalled {
if len(gpgSecretKeyRingFiles) == 0 && len(privKeys) == 0 && len(pkcs11Yamls) == 0 && len(keyProviders) == 0 && descs != nil {
// Get pgp private keys from keyring only if no private key was passed
gpgPrivKeys, gpgPrivKeyPasswords, err := getGPGPrivateKeys(context, gpgSecretKeyRingFiles, descs, true)
if err != nil {
return encconfig.CryptoConfig{}, err
}
gpgCc, err := encconfig.DecryptWithGpgPrivKeys(gpgPrivKeys, gpgPrivKeyPasswords)
if err != nil {
return encconfig.CryptoConfig{}, err
}
ccs = append(ccs, gpgCc)
} else if len(gpgSecretKeyRingFiles) > 0 {
gpgCc, err := encconfig.DecryptWithGpgPrivKeys(gpgSecretKeyRingFiles, gpgSecretKeyPasswords)
if err != nil {
return encconfig.CryptoConfig{}, err
}
ccs = append(ccs, gpgCc)
}
}
*/
if len(x509s) > 0 {
x509sCc, err := encconfig.DecryptWithX509s(x509s)
if err != nil {
return encconfig.CryptoConfig{}, err
}
ccs = append(ccs, x509sCc)
}
if len(privKeys) > 0 {
privKeysCc, err := encconfig.DecryptWithPrivKeys(privKeys, privKeysPasswords)
if err != nil {
return encconfig.CryptoConfig{}, err
}
ccs = append(ccs, privKeysCc)
}
if len(pkcs11Yamls) > 0 {
p11conf, err := pkcs11config.GetUserPkcs11Config()
if err != nil {
return encconfig.CryptoConfig{}, err
}
pkcs11PrivKeysCc, err := encconfig.DecryptWithPkcs11Yaml(p11conf, pkcs11Yamls)
if err != nil {
return encconfig.CryptoConfig{}, err
}
ccs = append(ccs, pkcs11PrivKeysCc)
}
if len(keyProviders) > 0 {
keyProviderCc, err := encconfig.DecryptWithKeyProvider(keyProviders)
if err != nil {
return encconfig.CryptoConfig{}, err
}
ccs = append(ccs, keyProviderCc)
}
return encconfig.CombineCryptoConfigs(ccs), nil
}
// CreateCryptoConfig from the list of recipient strings and list of key paths of private keys
func CreateCryptoConfig(recipients []string, keys []string) (encconfig.CryptoConfig, error) {
var decryptCc *encconfig.CryptoConfig
ccs := []encconfig.CryptoConfig{}
if len(keys) > 0 {
dcc, err := CreateDecryptCryptoConfig(keys, []string{})
if err != nil {
return encconfig.CryptoConfig{}, err
}
decryptCc = &dcc
ccs = append(ccs, dcc)
}
if len(recipients) > 0 {
gpgRecipients, pubKeys, x509s, pkcs11Pubkeys, pkcs11Yamls, keyProvider, err := processRecipientKeys(recipients)
if err != nil {
return encconfig.CryptoConfig{}, err
}
encryptCcs := []encconfig.CryptoConfig{}
// Create GPG client with guessed GPG version and default homedir
gpgClient, err := ocicrypt.NewGPGClient("", "")
gpgInstalled := err == nil
if len(gpgRecipients) > 0 && gpgInstalled {
gpgPubRingFile, err := gpgClient.ReadGPGPubRingFile()
if err != nil {
return encconfig.CryptoConfig{}, err
}
gpgCc, err := encconfig.EncryptWithGpg(gpgRecipients, gpgPubRingFile)
if err != nil {
return encconfig.CryptoConfig{}, err
}
encryptCcs = append(encryptCcs, gpgCc)
}
// Create Encryption Crypto Config
if len(x509s) > 0 {
pkcs7Cc, err := encconfig.EncryptWithPkcs7(x509s)
if err != nil {
return encconfig.CryptoConfig{}, err
}
encryptCcs = append(encryptCcs, pkcs7Cc)
}
if len(pubKeys) > 0 {
jweCc, err := encconfig.EncryptWithJwe(pubKeys)
if err != nil {
return encconfig.CryptoConfig{}, err
}
encryptCcs = append(encryptCcs, jweCc)
}
var p11conf *pkcs11.Pkcs11Config
if len(pkcs11Yamls) > 0 || len(pkcs11Pubkeys) > 0 {
p11conf, err = pkcs11config.GetUserPkcs11Config()
if err != nil {
return encconfig.CryptoConfig{}, err
}
pkcs11Cc, err := encconfig.EncryptWithPkcs11(p11conf, pkcs11Pubkeys, pkcs11Yamls)
if err != nil {
return encconfig.CryptoConfig{}, err
}
encryptCcs = append(encryptCcs, pkcs11Cc)
}
if len(keyProvider) > 0 {
keyProviderCc, err := encconfig.EncryptWithKeyProvider(keyProvider)
if err != nil {
return encconfig.CryptoConfig{}, err
}
encryptCcs = append(encryptCcs, keyProviderCc)
}
ecc := encconfig.CombineCryptoConfigs(encryptCcs)
if decryptCc != nil {
ecc.EncryptConfig.AttachDecryptConfig(decryptCc.DecryptConfig)
}
ccs = append(ccs, ecc)
}
if len(ccs) > 0 {
return encconfig.CombineCryptoConfigs(ccs), nil
}
return encconfig.CryptoConfig{}, nil
}