- From: Ryan Sleevi <sleevi@google.com>
- Date: Tue, 30 Oct 2012 02:04:36 -0700
- To: Mark Watson <watsonm@netflix.com>
- Cc: "public-webcrypto@w3.org Group" <public-webcrypto@w3.org>
On Tue, Oct 30, 2012 at 1:38 AM, Mark Watson <watsonm@netflix.com> wrote: > All, > > Here is a proposal in response to ISSUE-35 [1], using JWK (with extensions) > as the format for the key and associated parameters before wrapping. > Wrapping and unwrapping are considered aspects of key export and import > (respectively). To export/import without wrapping the user just specifies > the wrap algorithm as null. > > 1) Add "wrap" and "unwrap" to KeyUsage enum: > > "10. Key interface > > enum KeyUsage { > "encrypt", > "decrypt", > "sign", > "verify", > "wrap", > "unwrap", > };" > > 2) Add wrapped attribute to KeyImporter and KeyExporter. Specify the > character encoding of JSON Web Keys (we assume that all key export > operations result in an ArrayBufferView): > > "15. KeyImporter interface > > enum KeyFormat { > // An unformatted sequence of bytes. Intended for secret keys. > "raw", > // The BER encoding of the RSAPublicKey structure from RFC 3447. > // Only usable with RSA keys. > "pkcs1-public", > // The BER encoding of the RSAPrivateKey structure from RFC 3447. > // Only usable with RSA keys. > "pkcs1-private", > // The BER encoding of the PrivateKeyInfo structure from RFC 5208. > "pkcs8", > // The key is represented as UTF-8 encoded JSON according to the JSON Web > Key format. > "jwk" > }; > > interface KeyImporter : KeyOperation { > void import(); > > readonly attribute KeyFormat format; > readonly attribute boolean wrapped; > }; > > interface KeyExporter : KeyOperation { > void export(); > > readonly attribute KeyFormat format; > readonly attribute boolean wrapped; > }; > > 15.1. JSON Web Key > > Implementations SHOULD support additional JSON Web Key use values of: > • wrap (key wrapping) Is there a reason you didn't consider this a MUST? Note for readers - JWK currently only defines "sign" and "encrypt", and so there are a very different set of usages here. > Implementations SHOULD support additional JSON Web Key members of: > • extractable (boolean indicating extractability) > • startdate (key start date in seconds since the epoch) > • enddate (key end date in seconds since the epoch) Can you explain the difference between wrap and extractable here? In practical security considerations, they're better considered equal. As for startdate/enddate - - As previously discussed on the list, I thought (and will make a separate proposal) to remove the startDate/endDate attributes from the fundamental Key object (and let them be stored in the extra - since as both Vijay and I pointed out, they're application-specific notions) - If we do continue with it, "the epoch" is, regrettably, undefined. Whose epoch? Unix epoch of 1970? Windows epoch of 1601? > Implementations SHOULD expose additional JSON Web Key members as attributes > contained within the extra attribute of the Key objects. > > TODO: Specify encoding of key attributes of potentially arbitrary type into > extra attribute map One of the issues I see here is whether the 'extra' attribute map gets flattened in directly to the JWK (which you seem to be proposing?) or get stored in a secondary attribute (eg: 'extra' on the JWK). It seems you're proposing the former, but it would seem the latter is necessary (eg: what if there is an 'extra' attribute named 'alg' or 'keyid' ?) > TODO: Specify JWK formats for private and symmetric keys > TODO: Register the above values with IANA > TODO: Specify key compatibility between JWK algorithm names with WebCrypto > algorithm names." > > 3) Modify createKeyImporter and createKeyExporter to take optional wrapping > algorithm and key > > "18. Crypto interface > > KeyImporter createKeyImporter( KeyFormat format, > ArrayBufferView key, > AlgorithmIdentifier? keyAlgorithm, > AlgorithmIdentifier? wrapAlgorithm, > Key? wrappingKey, > bool temporary = true, > bool extractable = false, > KeyUsage[] keyUsages = [] ); > > KeyExporter createKeyExporter( KeyFormat format, > Key key, > AlgorithmIdentifier? wrapAlgorithm, > Key? wrappingKey ); > > "18.1.8 The createKeyImporter method > > The createKeyImporter method returns a new KeyImporter object that will > import > new keys of the, potentially wrapped, specified KeyFormat. It must act as > follows: > > 1. If keyAlgorithm is specified, let normalizedKeyAlgorithm be the result > of processing keyAlgorithm according to > the algorithm normalizing rules. > 2. If keyAlgorithm is specified and if normalizedKeyAlgorithm does not > describe a registered algorithm throw a > NotSupportedError and terminate the operation. > 3. If wrapAlgorithm is specified, let normalizedWrapAlgorithm be the > result of processing wrapAlgorithm according to > the algorithm normalizing rules. > 4. If wrapAlgorithm is specified and if normalizedWrapAlgorithm does not > describe a registered algorithm throw a > NotSupportedError and terminate the operation. > 5. Return a new KeyImporter object S with the following characteristics: > 1. S.result = null > 2. S.format = format > 3. S.wrapped = true if wrapAlgorithm is not null, false otherwise > > Imported keys SHALL be subject to the extraction and usage constraints of > the key > data, if any. The temporary argument SHALL be honored. The extractable > argument > SHALL NOT be honored if the key data does not allow extraction of the > imported key. The > imported key's usages SHALL consist of the intersection of the keyUsages > argument > and the usages specified in the key data of the imported key. > > The keyAlgorithm may be null if the key algorithm is specified within the > key data. > > 18.1.9 The createKeyExporter method > > The createKeyExporter method returns a new KeyExporter object that will > export > existing keys in the specified KeyFormat. It must act as follows: > > 1. If the key does not exist throw a KeyNotFoundError and terminate the > operation. > 2. If wrapAlgorithm is specified, let normalizedWrapAlgorithm be the > result of processing wrapAlgorithm according to > the algorithm normalizing rules. > 3. If wrapAlgorithm is specified and if normalizedWrapAlgorithm does not > describe a registered algorithm throw a > NotSupportedError and terminate the operation. > 4. If wrapAlgorithm is specified and wrappingKey is null, or if > wrapAlgorithm is null and wrappingKey is specified, throw a > NotSupportedError and terminate the operation > 4. If the wrappingKey is not null and does not exist throw a > KeyNotFoundError > and terminate the operation. > 5. Return a new KeyExporter object S with the following characteristics: > 1. S.result = null > 2. S.format = format > 3. S.wrapped = true if wrapAlgorithm is not null, false otherwise" > > 4) Add text on import/export for RSAES-PKCS1-v1_5 keys > > "24.3. RSAES-PKCS1-v1_5 > > 24.3.2. Registration > > The recognized algorithm name for this algorithm is "RSAES-PKCS1-v1_5". > > Operation | Parameters | Result > ================================================ > encrypt | None | ArrayBufferView? > decrypt | None | ArrayBufferView? > generateKey | RsaKeyGenParams | KeyPair? > importKey | None | Key? > exportKey | None | ArrayBufferView? > > 24.3.4 Operations > > Import Key > When importing a key, the resulting KeyImporter shall behave as follows: > > 1. Upon invoking import: > 1. If the key is wrapped, perform the unwrap operation defined for the > wrapAlgorithm > 2. Parse and extract the RSA key > 3. If either operation resulted in an error, raise an error and > terminate the > operation. > 4. Let result be a Key of the imported public or private key. > > Export Key > When exporting a key, the resulting KeyExporter shall behave as follows: > > 1. Upon invoking export: > 1. Encode the RSA key into the format > 2. If the key is to be wrapped, perform the wrap operation defined for > the wrapAlgorithm > 3. If either operation resulted in an error, raise an error and > terminate the > operation. > 4. Let result be an ArrayBufferView of the exported public or private > key." > > 5) Add text on import/export for RSASSA-PKCS1-v1_5 keys > > "24.4. RSASSA-PKCS1-v1_5 > > 24.4.2. Registration > > The recognized algorithm name for this algorithm is "RSASSA-PKCS1-v1_5". > > Operation | Parameters | Result > ================================================ > sign | RsaSsaParams | ArrayBufferView? > verify | RsaSsaParams | boolean? > generateKey | RsaKeyGenParams | KeyPair? > importKey | None | Key? > exportKey | None | ArrayBufferView? > > 24.4.4. Operations > > Import Key > When importing a key, the resulting KeyImporter shall behave as follows: > > 1. Upon invoking import: > 1. If the key is wrapped, perform the unwrap operation defined for the > wrapAlgorithm > 2. Parse and extract the RSA key > 3. If either operation resulted in an error, raise an error and > terminate the > operation. > 4. Let result be a Key of the imported public or private key. > > Export Key > When exporting a key, the resulting KeyExporter shall behave as follows: > > 1. Upon invoking export: > 1. Encode the RSA key into the format > 2. If the key is to be wrapped, perform the wrap operation defined for > the wrapAlgorithm > 3. If the operation resulted in an error, raise an error and terminate > the > operation. > 4. Let result be an ArrayBufferView of the exported public or private > key." > > 6) Add text on import/export for RSA-PSS keys > > "24.5. RSA-PSS > > 24.5.2. Registration > > The recognized algorithm name for this algorithm is "RSA-PSS". > > Operation | Parameters | Result > ================================================ > sign | RsaPssParams | ArrayBufferView? > verify | RsaPssParams | boolean? > generateKey | RsaKeyGenParams | KeyPair? > importKey | None | Key? > exportKey | None | ArrayBufferView? > > 24.4.4. Operations > > Import Key > When importing a key, the resulting KeyImporter shall behave as follows: > > 1. Upon invoking import: > 1. If the key is wrapped, perform the unwrap operation defined for the > wrapAlgorithm > 2. Parse and extract the RSA key > 3. If either operation resulted in an error, raise an error and > terminate the > operation. > 4. Let result be a Key of the imported public or private key. > > Export Key > When exporting a key, the resulting KeyExporter shall behave as follows: > > 1. Upon invoking export: > 1. Encode the RSA key into the format, including any wrap operations > as > dictated by the format and wrapAlgorithm. > 2. If the key is to be wrapped, perform the wrap operation defined for > the wrapAlgorithm > 3. If either operation resulted in an error, raise an error and > terminate the > operation. > 4. Let result be an ArrayBufferView of the exported public or private > key." > > 7) Add text on import/export for RSA-OAEP keys > > "24.6. RSA-OAEP > > 24.6.2. Registration > > The recognized algorithm name for this algorithm is "RSA-OAEP". > > Operation | Parameters | Result > ================================================ > encrypt | RsaOaepParams | ArrayBufferView? > decrypt | RsaOaepParams | ArrayBufferView? > generateKey | RsaKeyGenParams | KeyPair? > importKey | None | Key? > exportKey | None | ArrayBufferView? > > 24.6.4. Operations > > Import Key > When importing a key, the resulting KeyImporter shall behave as follows: > > 1. Upon invoking import: > 1. If the key is wrapped, perform the unwrap operation defined for the > wrapAlgorithm > 2. Parse and extract the RSA key > 3. If the operation resulted in an error, raise an error and terminate > the > operation. > 4. Let result be a Key of the imported public or private key. > > Export Key > When exporting a key, the resulting KeyExporter shall behave as follows: > > 1. Upon invoking export: > 1. Encode the RSA key into the format > 2. If the key is to be wrapped, perform the wrap operation defined for > the wrapAlgorithm > 3. If the operation resulted in an error, raise an error and terminate > the > operation. > 4. Let result be an ArrayBufferView of the exported public or private > key." > > 8) Add text on import/export for ECDSA keys > > "24.7. ECDSA > > 24.7.2. Registration > > The recognized algorithm name for this algorithm is "ECDSA". > > Operation | Parameters | Result > ================================================ > sign | EcdsaParams | ArrayBufferView? > verify | EcdsaParams | boolean? > generateKey | EcKeyGenParams | KeyPair? > importKey | None | Key? > exportKey | None | ArrayBufferView? > > 24.7.5. Operations > > Import Key > When importing a key, the resulting KeyImporter shall behave as follows: > > 1. Upon invoking import: > 1. If the key is wrapped, perform the unwrap operation defined for the > wrapAlgorithm > 2. Parse and extract the ECC key > 3. If either operation resulted in an error, raise an error and > terminate the > operation. > 4. Let result be a Key of the imported public or private key. > > Export Key > When exporting a key, the resulting KeyExporter shall behave as follows: > > 1. Upon invoking export: > 1. Encode the ECC key into the format > 2. If the key is to be wrapped, perform the wrap operation defined for > the wrapAlgorithm > 3. If either operation resulted in an error, raise an error and > terminate the > operation. > 4. Let result be an ArrayBufferView of the exported public or private > key." > > 9) Add import/export for AES-CTR keys > > "24.9. AES-CTR > > 24.9.2. Registration > > The recognized algorithm name for this algorithm is "AES-CTR". > > Operation | Parameters | Result > ================================================ > encrypt | AesCtrParams | ArrayBufferView? > decrypt | AesCtrParams | ArrayBufferView? > generateKey | AesKeyGenParams | Key? > importKey | None | Key? > exportKey | None | ArrayBufferView? > > 24.9.5. Operations > > Import Key > When importing a key, the resulting KeyImporter shall behave as follows: > > 1. Upon invoking import: > 1. If the key is wrapped, perform the unwrap operation defined for the > wrapAlgorithm > 2. Parse and extract the AES key > 3. If the operation resulted in an error, raise an error and terminate > the > operation. > 4. Let result be a Key of the imported secret key. > > Export Key > When exporting a key, the resulting KeyExporter shall behave as follows: > > 1. Upon invoking export: > 1. Encode the AES key into the format > 2. If the key is to be wrapped, perform the wrap operation defined for > the wrapAlgorithm > 3. If the operation resulted in an error, raise an error and terminate > the > operation. > 4. Let result be an ArrayBufferView of the exported secret key." > > 10) Add import/export for AES-CBC keys > > "24.10. AES-CBC > > 24.10.2. Registration > > The recognized algorithm name for this algorithm is "AES-CBC". > > Operation | Parameters | Result > ================================================ > encrypt | AesCbcParams | ArrayBufferView? > decrypt | AesCbcParams | ArrayBufferView? > generateKey | AesKeyGenParams | Key? > importKey | None | Key? > exportKey | None | ArrayBufferView? > > 24.10.4. Operations > > Import Key > When importing a key, the resulting KeyImporter shall behave as follows: > > 1. Upon invoking import: > 1. If the key is wrapped, perform the unwrap operation defined for the > wrapAlgorithm > 2. Parse and extract the AES key. > 3. If the operation resulted in an error, raise an error and terminate > the > operation. > 4. Let result be a Key of the imported secret key. > > Export Key > When exporting a key, the resulting KeyExporter shall behave as follows: > > 1. Upon invoking export: > 1. Encode the AES key into the format > 2. If the key is to be wrapped, perform the wrap operation defined for > the wrapAlgorithm > 3. If the operation resulted in an error, raise an error and terminate > the > operation. > 4. Let result be an ArrayBufferView of the exported secret key." > > 11) Add import/export for AES-GCM keys > > "24.11. AES-GCM > > 24.11.2. Registration > > The recognized algorithm name for this algorithm is "AES-GCM". > > Operation | Parameters | Result > ================================================ > encrypt | AesGcmParams | ArrayBufferView? > decrypt | AesGcmParams | ArrayBufferView? > generateKey | AesKeyGenParams | Key? > importKey | None | Key? > exportKey | None | ArrayBufferView? > > 24.11.4. Operations > > Import Key > When importing a key, the resulting KeyImporter shall behave as follows: > > 1. Upon invoking import: > 1. If the key is wrapped, perform the unwrap operation defined for the > wrapAlgorithm > 2. Parse and extract the AES key > 3. If the operation resulted in an error, raise an error and terminate > the > operation. > 4. Let result be a Key of the imported secret key. > > Export Key > When exporting a key, the resulting KeyExporter shall behave as follows: > > 1. Upon invoking export: > 1. Encode the AES key into the format > 2. If the key is to be wrapped, perform the wrap operation defined for > the wrapAlgorithm > 3. If either operation resulted in an error, raise an error and > terminate the > operation. > 4. Let result be an ArrayBufferView of the exported secret key." > > 12) Add import/export for HMAC keys > > "24.12. HMAC > > 24.12.2. Registration > > The recognized algorithm name for this algorithm is "HMAC". > > Operation | Parameters | Result > ================================================ > sign | HmacParams | ArrayBufferView? > verify | HmacParams | boolean? > generateKey | HmacKeyGenParams | Key? > importKey | None | Key? > exportKey | None | ArrayBufferView? > > 24.12.4. HmacKeyGenParams dictionary > > dictionary HmacKeyGenParams : AlgorithmParameters { > // The inner hash function to use. > AlgorithmIdentifier hash; > }; > > 24.12.5. Operations > > Import Key > When importing a key, the resulting KeyImporter shall behave as follows: > > 1. Upon invoking import: > 1. If the key is wrapped, perform the unwrap operation defined for the > wrapAlgorithm > 2. Parse and extract the HMAC key > 3. If either operation resulted in an error, raise an error and > terminate the > operation. > 4. Let result be a Key of the imported public or private key. > > Export Key > When exporting a key, the resulting KeyExporter shall behave as follows: > > 1. Upon invoking export: > 1. Encode the HMAC key into the format > 2. If the key is to be wrapped, perform the wrap operation defined for > the wrapAlgorithm > 3. If either operation resulted in an error, raise an error and > terminate the > operation. > 4. Let result be an ArrayBufferView of the exported public or private > key." > There are various issues regarding the copy/paste of text here, but those are minor and presumably would be fixed during editor integration. Just noting for future work. > 13) Add AES Key wrap algorithm > > "24.16 AES Key Wrap > > 24.16.1 Description > > The AES Key Wrap algorithm is described in RFC3394. This specification also > requires the use of padding according to RFC5649 in order to support wrapped > keys of arbitrary size. "requires" is a weak word here. Would you say that it's a correct interpretation that AES Key Wrap algorithm MUST support RFC 5649? > > 24.16.2 Registration > > The recognized algorithm name for this algorithm is "AES-KW". > > Operation | Parameters | Result > ================================================ > generateKey | AesKeyGenParams | Key > importKey | None | Key > exportKey | None | ArrayBufferView > wrap | None | ArrayBufferView > unwrap | None | Key I must admit, I'm not entirely sure I follow the distinction between the wrap/unwrap operation here for AES-KW, and all of the import/export additions/changes to the other algorithms. It seems only one or the other is necessary/appropriate? Have I missed something? > > 24.16.3 Operations > > Import Key > When importing a key, the resulting KeyImporter shall behave as follows: > > 1. Upon invoking import: > 1. If the key is wrapped, perform the unwrap operation defined for the > wrapAlgorithm > 2. Parse and extract the AES Key Wrap key > 3. If the operation resulted in an error, raise an error and terminate > the > operation. > 4. Let result be a Key of the imported public or private key. > > Export Key > When exporting a key, the resulting KeyExporter shall behave as follows: > > 1. Upon invoking export: > 1. Encode the AES Key Wrap key into the format > 2. If the key is to be wrapped, perform the wrap operation defined for > the wrapAlgorithm > 3. If the operation resulted in an error, raise an error and terminate > the > operation. > 4. Let result be an ArrayBufferView of the exported public or private > key. > > Unwrap: > > When unwrapping and importing a wrapped key, the following unwrapping steps > shall be performed first, followed by the steps of the importKey operation > for the appropriate key algorithm: > > 1. If the wrapKey is not an AES Key Wrap key, throw a NotSupporterError and > terminate the operation > 2. Apply the RFC5649 unwrapping operation to the provided key, using the > wrapKey > 1. If the result of the unwrapping operation is a failure of the data > integrity check, raise an error and terminate the operation > 2. Otherwise, if the key data specifies a key algorithm > 1. if the keyAlgorithm parameter to the import operation is not null and the > key algorithm specified by the key data is not compatible with the > keyAlgorithm parameter, raise an error and terminate the operation. Can you clarify a bit on "key algorithm specified by the key data". It sounds like you mean translating the JWK alg (aka a JWA) into a Web Crypto alg, and then comparing them. Is that correct? What if the keyAlgorithm parameters specifies parameters that cannot be encoded within JWA? Are those comparable/compatible? Is there some normalization that needs to occur before comparison? If we do go with this, I would almost suggest dropping the comparison entirely - letting the algorithm be fully dictated by the unwrapper/importer. > 2. Otherwise, if the keyAlgorithm parameter is null, set the key algorithm > to be the key algorithm specified by the key data > 3. Continue the key import operation using the output of the unwrap > operation according to the requirements of the key algorithm > > Wrap > > When wrapping and exporting a key, the resulting key exporter shall behave > according to the specification of the key algorithm with the following > additional requirements for the wrapping step: > > 1. If the wrapKey is not an AES Key Wrap key, throw a NotSupporterError and > terminate the operation > 2. Apply the RFC5649 wrapping operation to the output of the key export > operation > 3. Let the result be an ArrayBufferView of the exported, wrapped, key" > > 14) Provide an example of wrapped key import > > "26.4 Wrapped key import > > // The key type, exportability, start and end time are specified in the JWK > structure. > // It is assumed JWK is extended to support private and symmetric keys. > // For example, the following could describe an AES CTR encryption key (note > this uses values > // not specified in JWK which so far only addresses public keys. However, > JWK can be extended > // on a 'specification required' basis through registration with IANA). > // > // keyJwk = { "use" : "enc", "alg" : "A256", "exportable" : false, "key" : > "56giug87f298gf9724gf9==" } > // > // for the purposes of this example, wrappedKeyJwk = AESKeyWrap( keyJwk, > wrappingKey ) > > var keyImporter = window.crypto.createKeyImporter( "jwk", > wrappedKeyJwk, > "AES-CTR", > "AES-KW", > wrappingKey, > true, // temporary > true, // extractable > [ "encrypt" ] ); > keyImporter.onComplete = function(event) { > var key = event.target.result; > console.log("Imported key ID: " + key.id + "; algorithm " + > key.algorithm.name + "; exportable " + key.exportable ); > }; > keyImporter.import(); > > In the above example, the final output should indicate "exportable false", > because the exportable attribute in the wrapped JWK structure is set to > false." If you've wrapped a key into JWK, I would strongly suggest that you just exported it :) For example, using a known/fixed-by-an-attacker Key Wrapping Key in order to export the un-extractable/un-exportable key would allow me to easily recover the original key text. > > [1] http://www.w3.org/2012/webcrypto/track/issues/35
Received on Tuesday, 30 October 2012 09:05:11 UTC