summaryrefslogtreecommitdiff
path: root/lib/freebl/rijndael.c
diff options
context:
space:
mode:
authorRobert Relyea <rrelyea@redhat.com>2020-03-19 09:52:01 -0700
committerRobert Relyea <rrelyea@redhat.com>2020-03-19 09:52:01 -0700
commit60c7273fb0b16b786c2562fd42e81e5f99126c33 (patch)
treee6e9a3c0498582b11fc338464abb5995ce161178 /lib/freebl/rijndael.c
parent8532767a723ddd02329abd89eec269fec97a29a8 (diff)
downloadnss-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.c60
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);
+}