diff options
author | Robert Relyea <rrelyea@redhat.com> | 2020-03-19 09:52:01 -0700 |
---|---|---|
committer | Robert Relyea <rrelyea@redhat.com> | 2020-03-19 09:52:01 -0700 |
commit | 60c7273fb0b16b786c2562fd42e81e5f99126c33 (patch) | |
tree | e6e9a3c0498582b11fc338464abb5995ce161178 /lib/freebl/rijndael.c | |
parent | 8532767a723ddd02329abd89eec269fec97a29a8 (diff) | |
download | nss-hg-60c7273fb0b16b786c2562fd42e81e5f99126c33.tar.gz |
Bug 1623374 Need to support the new PKCS #11 Message interface for AES GCM and ChaCha Poly
PKCS #11 defines a new interface for handling AEAD type ciphers that allow
multiple AEAD operations without repeating the key schedule. It also allows
tokens to keep track of the number of operations, and generate IVs (depending
on the cipher).
This patch:
1. implement those new functions in softoken.
With the addition of CKF_MESSAGE_* flags to various mechanism, we need
to strip them when using the version 2 API of softoken (since there are
no C_Message* function in version 2). For that we need a separate
C_GetMechanismInfo function. We use the same trick we used to have
a separate version function for the V2 interface.
Also now that the new message functions are in their own file, they
still need access to the common Session state processing functions.
those have gone from static to exported within softoken to accomidate
that. Same with sftk_MapDecryptError() (sftk_MapVerifyError() was also
made global, though nothing else is yet using it).
Only C_MessageEncrptInit(), C_EncryptMessage(), C_MessageEncryptFinal,
C_MessageDecryptInit(), C_DecryptMessage(), and C_MessageDecryptFinal
are implemented. C_EncryptMessageBegin(), C_EncryptMessageNext(),
C_DecryptMessageBegin(), and C_DecryptMessageNext() are all
part of the multi-part withing a multi-part operation and
are only necessary for things like S/MIME (potentially). If we wanted
to implement them, we would need more functions exported from freebl
(and initaead, updateaead, finalaead for each mechanism type).
2. make those interfaces call aes_gcm and chacha20_poly1503
(and make adjustments for those ciphers).
For AES, I added a new function AES_AEAD, which handles both encrypt
and decrypt. Internally, the gcm functions (both the generic gcm and
the intel gcm wrapper) had their init functions split into key scheduling
and counter mode/tag initialization. The latter is still called from
init, but the former is now for each update call. IV generation is
handled by a single function in gcm.c, and shared with intel_gcm_wrapper.c
Since the AES functions already know about the underlying PKCS #11
mechanism parameters, the new AEAD functions also parse the PKCS #11 GCM
parameters.
For Chacha/Poly new aead update functions were created called
ChaChaPoly1305_Encrypt and ChaChaChaPoly1305_Decrypt. There was no
Message specific initialization in the existing chacha_init, so no
changes were needed there. The primary difference between
_Encrypt/_Decrypt and _Seal/_Open is the fact that the tag is put at
the end of the encrypted data buffer in the latter, and in a generic
buffer in the former.
3. create new pk11wrap interfaces that also squash the api differences
between the various mechanisms for aead (similiar to the way we do it for
CBC and ECB crypto today).
To accomplish this I added PK11_AEADOp() and PK11_AEADRawOp(). Both
functions handle the case where the token only supports the single shot
interface, by using the single short interface to simulate the
Message interface. The PK11_AEADOp() also smooths out the
differences in the parameters and symantics of the various mechanism
so the application does not need to worry about the PKCS #11 differences
in the mechanism. Both use contexts from the standard
PK11_CreateContext(), so key schedules are done once for each key rather
than once for each message. MESSAGE/AEAD operations are selected by adding
the psuedo attribute flag CKA_NSS_MESSAGE to the requested operation
(CKA_ENCRYPT, CKA_DECRYPT, CKA_SIGN, CKA_VERIFY).
4. write tests for the new interfaces
Tests were added to make sure the PK11_AEADRawOp interface works,
The single shot interface is used to test output of the message interface
we also use two test only functions to force the connection to use
the simulation interface, which is also compared to the non-simulate
inteface. The AES_GCM also tests various IV generators.
Differential Revision: https://phabricator.services.mozilla.com/D67552
Diffstat (limited to 'lib/freebl/rijndael.c')
-rw-r--r-- | lib/freebl/rijndael.c | 60 |
1 files changed, 59 insertions, 1 deletions
diff --git a/lib/freebl/rijndael.c b/lib/freebl/rijndael.c index 247a9419b..449557cbe 100644 --- a/lib/freebl/rijndael.c +++ b/lib/freebl/rijndael.c @@ -999,6 +999,7 @@ AES_InitContext(AESContext *cx, const unsigned char *key, unsigned int keysize, } /* finally, set up any mode specific contexts */ + cx->worker_aead = 0; switch (mode) { case NSS_AES_CTS: cx->worker_cx = CTS_CreateContext(cx, cx->worker, iv); @@ -1013,6 +1014,8 @@ AES_InitContext(AESContext *cx, const unsigned char *key, unsigned int keysize, cx->worker_cx = intel_AES_GCM_CreateContext(cx, cx->worker, iv); cx->worker = (freeblCipherFunc)(encrypt ? intel_AES_GCM_EncryptUpdate : intel_AES_GCM_DecryptUpdate); + cx->worker_aead = (freeblAeadFunc)(encrypt ? intel_AES_GCM_EncryptAEAD + : intel_AES_GCM_DecryptAEAD); cx->destroy = (freeblDestroyFunc)intel_AES_GCM_DestroyContext; cx->isBlock = PR_FALSE; } else @@ -1021,6 +1024,9 @@ AES_InitContext(AESContext *cx, const unsigned char *key, unsigned int keysize, cx->worker_cx = GCM_CreateContext(cx, cx->worker, iv); cx->worker = (freeblCipherFunc)(encrypt ? GCM_EncryptUpdate : GCM_DecryptUpdate); + cx->worker_aead = (freeblAeadFunc)(encrypt ? GCM_EncryptAEAD + : GCM_DecryptAEAD); + cx->destroy = (freeblDestroyFunc)GCM_DestroyContext; cx->isBlock = PR_FALSE; } @@ -1170,7 +1176,7 @@ AES_Decrypt(AESContext *cx, unsigned char *output, PORT_SetError(SEC_ERROR_INPUT_LEN); return SECFailure; } - if (maxOutputLen < inputLen) { + if ((cx->mode != NSS_AES_GCM) && (maxOutputLen < inputLen)) { PORT_SetError(SEC_ERROR_OUTPUT_LEN); return SECFailure; } @@ -1178,3 +1184,55 @@ AES_Decrypt(AESContext *cx, unsigned char *output, return (*cx->worker)(cx->worker_cx, output, outputLen, maxOutputLen, input, inputLen, AES_BLOCK_SIZE); } + +/* + * AES_Encrypt_AEAD + * + * Encrypt using GCM or CCM. include the nonce, extra data, and the tag + */ +SECStatus +AES_AEAD(AESContext *cx, unsigned char *output, + unsigned int *outputLen, unsigned int maxOutputLen, + const unsigned char *input, unsigned int inputLen, + void *params, unsigned int paramsLen, + const unsigned char *aad, unsigned int aadLen) +{ + /* Check args */ + if (cx == NULL || output == NULL || (input == NULL && inputLen != 0) || (aad == NULL && aadLen != 0) || params == NULL) { + PORT_SetError(SEC_ERROR_INVALID_ARGS); + return SECFailure; + } + if (cx->worker_aead == NULL) { + PORT_SetError(SEC_ERROR_NOT_INITIALIZED); + return SECFailure; + } + if (maxOutputLen < inputLen) { + PORT_SetError(SEC_ERROR_OUTPUT_LEN); + return SECFailure; + } + *outputLen = inputLen; +#if UINT_MAX > MP_32BIT_MAX + /* + * we can guarentee that GSM won't overlfow if we limit the input to + * 2^36 bytes. For simplicity, we are limiting it to 2^32 for now. + * + * We do it here to cover both hardware and software GCM operations. + */ + { + PR_STATIC_ASSERT(sizeof(unsigned int) > 4); + } + if (inputLen > MP_32BIT_MAX) { + PORT_SetError(SEC_ERROR_OUTPUT_LEN); + return SECFailure; + } +#else + /* if we can't pass in a 32_bit number, then no such check needed */ + { + PR_STATIC_ASSERT(sizeof(unsigned int) <= 4); + } +#endif + + return (*cx->worker_aead)(cx->worker_cx, output, outputLen, maxOutputLen, + input, inputLen, params, paramsLen, aad, aadLen, + AES_BLOCK_SIZE); +} |