Add support for cosign encrypted private keys
I have a private key made by cosign which errors during inspect, specifically in the call to asn1.Unmarshall.
With the minimal example it should be easy to recreate the issue - frankly I'm not sure if this is smallstep bug or issue, so please close if appropriate :)
> cosign generate-key-pair
Enter password for private key:
Enter again:
Private key written to cosign.key
Public key written to cosign.pub
> sed -i 's/ENCRYPTED COSIGN PRIVATE KEY/ENCRYPTED PRIVATE KEY/g' cosign.key
> step crypto key inspect cosign.key
Please enter the password to decrypt cosign.key:
error decrypting cosign.key: failed to unmarshal private key: asn1: structure error: tags don't match (16 vs {class:1 tag:27 length:34 isCompound:true}) {optional:false explicit:false application:false private:false defaultValue:<nil> tag:<nil> stringType:0 timeType:0 set:false omitEmpty:false} encryptedPrivateKeyInfo @2
As mentioned on gitter, the data "payload" of the private key from cosign looks like following, whereas keys created by step crypto keypair appear to have a binary "payload". Following is from debug print statements in pkcs8.go:
{
"kdf": {
"name": "scrypt",
"params": {
"N": 32768,
"r": 8,
"p": 1
},
"salt": "r2LB ..snip.. AQcc="
},
"cipher": {
"name": "nacl/secretbox",
"nonce": "nYWq ..snip.. UkhYE"
},
"ciphertext": "RXCC ..snip.. hTpA=="
}
I've been looking at this, and the problem is that cosign does not use the PKCS#8 encryption defined in RFC7468. They use encryption based on NaCl SecretBox using a secret derived from the given password using scrypt.
The implementation is in the encrypted package of https://github.com/theupdateframework/go-tuf, and I can't find the definition of the encryption in the TUF spec
Assuming you are on the Sigstore Slack, there is some useful info here in a thread.
To quote from Dan Lorenc on that thread:
There are many ways to store the keys on disk Cosign keys are encrypted using nacl secret box But otherwise they're just plain ecdsa keys So cosign first decrypts that (after checking the header) Then even after that step there are many ways of representing an ec keypair, we assume they're in the asn.1 format
So if I understand this right, I can use the commands in https://smallstep.com/docs/step-cli/reference/crypto/nacl/secretbox to work with cosign keys
@mafrosis yes, and not. To use step crypto nacl secretbox, you first will need to derive the secretbox key from the password using scrypt. Step supports scrypt, but as it doesn't allow you to set the salt, so you cannot derive the proper key just using step.
In any case, we will add support to these keys in go.step.sm/crypto.
@mafrosis just hacked this to add support in the cli https://github.com/smallstep/crypto/pull/20