aboutsummaryrefslogtreecommitdiff
path: root/sys/opencrypto/cryptosoft.c
diff options
context:
space:
mode:
Diffstat (limited to 'sys/opencrypto/cryptosoft.c')
-rw-r--r--sys/opencrypto/cryptosoft.c124
1 files changed, 94 insertions, 30 deletions
diff --git a/sys/opencrypto/cryptosoft.c b/sys/opencrypto/cryptosoft.c
index ae71f0d6c096..e51bade8a3f8 100644
--- a/sys/opencrypto/cryptosoft.c
+++ b/sys/opencrypto/cryptosoft.c
@@ -636,16 +636,69 @@ out:
return (error);
}
+static void
+build_ccm_b0(const char *nonce, u_int nonce_length, u_int aad_length,
+ u_int data_length, u_int tag_length, uint8_t *b0)
+{
+ uint8_t *bp;
+ uint8_t flags, L;
+
+ KASSERT(nonce_length >= 7 && nonce_length <= 13,
+ ("nonce_length must be between 7 and 13 bytes"));
+
+ /*
+ * Need to determine the L field value. This is the number of
+ * bytes needed to specify the length of the message; the length
+ * is whatever is left in the 16 bytes after specifying flags and
+ * the nonce.
+ */
+ L = 15 - nonce_length;
+
+ flags = ((aad_length > 0) << 6) +
+ (((tag_length - 2) / 2) << 3) +
+ L - 1;
+
+ /*
+ * Now we need to set up the first block, which has flags, nonce,
+ * and the message length.
+ */
+ b0[0] = flags;
+ memcpy(b0 + 1, nonce, nonce_length);
+ bp = b0 + 1 + nonce_length;
+
+ /* Need to copy L' [aka L-1] bytes of data_length */
+ for (uint8_t *dst = b0 + CCM_CBC_BLOCK_LEN - 1; dst >= bp; dst--) {
+ *dst = data_length;
+ data_length >>= 8;
+ }
+}
+
+/* NB: OCF only supports AAD lengths < 2^32. */
+static int
+build_ccm_aad_length(u_int aad_length, uint8_t *blk)
+{
+ if (aad_length < ((1 << 16) - (1 << 8))) {
+ be16enc(blk, aad_length);
+ return (sizeof(uint16_t));
+ } else {
+ blk[0] = 0xff;
+ blk[1] = 0xfe;
+ be32enc(blk + 2, aad_length);
+ return (2 + sizeof(uint32_t));
+ }
+}
+
static int
swcr_ccm_cbc_mac(struct swcr_session *ses, struct cryptop *crp)
{
- u_char tag[AES_CBC_MAC_HASH_LEN];
u_char iv[AES_BLOCK_LEN];
+ u_char blk[CCM_CBC_BLOCK_LEN];
+ u_char tag[AES_CBC_MAC_HASH_LEN];
union authctx ctx;
const struct crypto_session_params *csp;
struct swcr_auth *swa;
const struct auth_hash *axf;
- int error, ivlen;
+ int error, ivlen, len;
csp = crypto_get_params(crp->crp_session);
swa = &ses->swcr_auth;
@@ -657,25 +710,24 @@ swcr_ccm_cbc_mac(struct swcr_session *ses, struct cryptop *crp)
ivlen = csp->csp_ivlen;
crypto_read_iv(crp, iv);
- /*
- * AES CCM-CBC-MAC needs to know the length of both the auth
- * data and payload data before doing the auth computation.
- */
- ctx.aes_cbc_mac_ctx.authDataLength = crp->crp_payload_length;
- ctx.aes_cbc_mac_ctx.cryptDataLength = 0;
+ /* Supply MAC with IV */
+ axf->Reinit(&ctx, crp->crp_iv, ivlen);
- axf->Reinit(&ctx, iv, ivlen);
- if (crp->crp_aad != NULL)
- error = axf->Update(&ctx, crp->crp_aad, crp->crp_aad_length);
- else
- error = crypto_apply(crp, crp->crp_payload_start,
- crp->crp_payload_length, axf->Update, &ctx);
- if (error)
- return (error);
+ /* Supply MAC with b0. */
+ build_ccm_b0(crp->crp_iv, ivlen, crp->crp_payload_length, 0,
+ swa->sw_mlen, blk);
+ axf->Update(&ctx, blk, CCM_CBC_BLOCK_LEN);
+
+ len = build_ccm_aad_length(crp->crp_payload_length, blk);
+ axf->Update(&ctx, blk, len);
+
+ crypto_apply(crp, crp->crp_payload_start, crp->crp_payload_length,
+ axf->Update, &ctx);
/* Finalize MAC */
axf->Final(tag, &ctx);
+ error = 0;
if (crp->crp_op & CRYPTO_OP_VERIFY_DIGEST) {
u_char tag2[AES_CBC_MAC_HASH_LEN];
@@ -689,6 +741,7 @@ swcr_ccm_cbc_mac(struct swcr_session *ses, struct cryptop *crp)
crypto_copyback(crp, crp->crp_digest_start, swa->sw_mlen, tag);
}
explicit_bzero(tag, sizeof(tag));
+ explicit_bzero(blk, sizeof(blk));
explicit_bzero(iv, sizeof(iv));
return (error);
}
@@ -733,24 +786,35 @@ swcr_ccm(struct swcr_session *ses, struct cryptop *crp)
ivlen = csp->csp_ivlen;
- /*
- * AES CCM-CBC-MAC needs to know the length of both the auth
- * data and payload data before doing the auth computation.
- */
- ctx.aes_cbc_mac_ctx.authDataLength = crp->crp_aad_length;
- ctx.aes_cbc_mac_ctx.cryptDataLength = crp->crp_payload_length;
-
/* Supply MAC with IV */
axf->Reinit(&ctx, crp->crp_iv, ivlen);
+ /* Supply MAC with b0. */
+ _Static_assert(sizeof(blkbuf) >= CCM_CBC_BLOCK_LEN,
+ "blkbuf too small for b0");
+ build_ccm_b0(crp->crp_iv, ivlen, crp->crp_aad_length,
+ crp->crp_payload_length, swa->sw_mlen, blk);
+ axf->Update(&ctx, blk, CCM_CBC_BLOCK_LEN);
+
/* Supply MAC with AAD */
- if (crp->crp_aad != NULL)
- error = axf->Update(&ctx, crp->crp_aad, crp->crp_aad_length);
- else
- error = crypto_apply(crp, crp->crp_aad_start,
- crp->crp_aad_length, axf->Update, &ctx);
- if (error)
- return (error);
+ if (crp->crp_aad_length != 0) {
+ len = build_ccm_aad_length(crp->crp_aad_length, blk);
+ axf->Update(&ctx, blk, len);
+ if (crp->crp_aad != NULL)
+ axf->Update(&ctx, crp->crp_aad,
+ crp->crp_aad_length);
+ else
+ crypto_apply(crp, crp->crp_aad_start,
+ crp->crp_aad_length, axf->Update, &ctx);
+
+ /* Pad the AAD (including length field) to a full block. */
+ len = (len + crp->crp_aad_length) % CCM_CBC_BLOCK_LEN;
+ if (len != 0) {
+ len = CCM_CBC_BLOCK_LEN - len;
+ memset(blk, 0, CCM_CBC_BLOCK_LEN);
+ axf->Update(&ctx, blk, len);
+ }
+ }
if (crp->crp_cipher_key != NULL)
exf->setkey(swe->sw_kschedule, crp->crp_cipher_key,