- 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