diff options
Diffstat (limited to 'usr/src/uts/common/crypto/io/dprov.c')
-rw-r--r-- | usr/src/uts/common/crypto/io/dprov.c | 111 |
1 files changed, 111 insertions, 0 deletions
diff --git a/usr/src/uts/common/crypto/io/dprov.c b/usr/src/uts/common/crypto/io/dprov.c index e08a70dcaf..a6a070ad6a 100644 --- a/usr/src/uts/common/crypto/io/dprov.c +++ b/usr/src/uts/common/crypto/io/dprov.c @@ -231,6 +231,7 @@ typedef enum dprov_mech_type { AES_ECB_MECH_INFO_TYPE, /* SUN_CKM_AES_ECB */ AES_CTR_MECH_INFO_TYPE, /* SUN_CKM_AES_CTR */ AES_CCM_MECH_INFO_TYPE, /* SUN_CKM_AES_CCM */ + AES_GCM_MECH_INFO_TYPE, /* SUN_CKM_AES_CCM */ RC4_MECH_INFO_TYPE, /* SUN_CKM_RC4 */ RSA_PKCS_MECH_INFO_TYPE, /* SUN_CKM_RSA_PKCS */ RSA_X_509_MECH_INFO_TYPE, /* SUN_CKM_RSA_X_509 */ @@ -495,6 +496,13 @@ static crypto_mech_info_t dprov_mech_info_tab[] = { CRYPTO_FG_DECRYPT_ATOMIC | CRYPTO_FG_ENCRYPT_MAC_ATOMIC | CRYPTO_FG_MAC_DECRYPT_ATOMIC, AES_MIN_KEY_LEN, AES_MAX_KEY_LEN, CRYPTO_KEYSIZE_UNIT_IN_BYTES}, + /* AES-GCM */ + {SUN_CKM_AES_GCM, AES_GCM_MECH_INFO_TYPE, + CRYPTO_FG_ENCRYPT | CRYPTO_FG_DECRYPT | CRYPTO_FG_ENCRYPT_MAC | + CRYPTO_FG_MAC_DECRYPT | CRYPTO_FG_ENCRYPT_ATOMIC | + CRYPTO_FG_DECRYPT_ATOMIC | CRYPTO_FG_ENCRYPT_MAC_ATOMIC | + CRYPTO_FG_MAC_DECRYPT_ATOMIC, + AES_MIN_KEY_LEN, AES_MAX_KEY_LEN, CRYPTO_KEYSIZE_UNIT_IN_BYTES}, /* RC4 */ {SUN_CKM_RC4, RC4_MECH_INFO_TYPE, CRYPTO_FG_ENCRYPT | CRYPTO_FG_ENCRYPT_ATOMIC | @@ -2298,6 +2306,7 @@ dprov_valid_cipher_mech(crypto_mech_type_t mech_type) mech_type == AES_ECB_MECH_INFO_TYPE || mech_type == AES_CTR_MECH_INFO_TYPE || mech_type == AES_CCM_MECH_INFO_TYPE || + mech_type == AES_GCM_MECH_INFO_TYPE || mech_type == RC4_MECH_INFO_TYPE || mech_type == RSA_PKCS_MECH_INFO_TYPE || mech_type == RSA_X_509_MECH_INFO_TYPE || @@ -4371,6 +4380,88 @@ out: return (rv); } +/* + * Resource control checks don't need to be done. Why? Because this routine + * knows the size of the structure, and it can't be overridden by a user. + * This is different from the crypto module, which has no knowledge of + * specific mechanisms, and therefore has to trust specified size of the + * parameter. This trust, or lack of trust, is why the size of the + * parameter has to be charged against the project resource control. + */ +static int +copyin_aes_gcm_mech(crypto_mechanism_t *in_mech, crypto_mechanism_t *out_mech, + int *out_error, int mode) +{ + STRUCT_DECL(crypto_mechanism, mech); + STRUCT_DECL(CK_AES_GCM_PARAMS, params); + CK_AES_GCM_PARAMS *aes_gcm_params; + caddr_t pp; + size_t param_len; + int error = 0; + int rv = 0; + + STRUCT_INIT(mech, mode); + STRUCT_INIT(params, mode); + bcopy(in_mech, STRUCT_BUF(mech), STRUCT_SIZE(mech)); + pp = STRUCT_FGETP(mech, cm_param); + param_len = STRUCT_FGET(mech, cm_param_len); + + if (param_len != STRUCT_SIZE(params)) { + rv = CRYPTO_ARGUMENTS_BAD; + goto out; + } + + out_mech->cm_type = STRUCT_FGET(mech, cm_type); + out_mech->cm_param = NULL; + out_mech->cm_param_len = 0; + if (pp != NULL) { + size_t nonce_len, auth_data_len, total_param_len; + + if (copyin((char *)pp, STRUCT_BUF(params), param_len) != 0) { + out_mech->cm_param = NULL; + error = EFAULT; + goto out; + } + + nonce_len = STRUCT_FGET(params, ulIvLen); + auth_data_len = STRUCT_FGET(params, ulAADLen); + + /* allocate param structure */ + total_param_len = + sizeof (CK_AES_GCM_PARAMS) + nonce_len + auth_data_len; + aes_gcm_params = kmem_alloc(total_param_len, KM_NOSLEEP); + if (aes_gcm_params == NULL) { + rv = CRYPTO_HOST_MEMORY; + goto out; + } + aes_gcm_params->ulTagBits = STRUCT_FGET(params, ulTagBits); + aes_gcm_params->ulIvLen = nonce_len; + aes_gcm_params->ulAADLen = auth_data_len; + aes_gcm_params->pIv + = (uchar_t *)aes_gcm_params + sizeof (CK_AES_GCM_PARAMS); + aes_gcm_params->pAAD = aes_gcm_params->pIv + nonce_len; + + if (copyin((char *)STRUCT_FGETP(params, pIv), + aes_gcm_params->pIv, nonce_len) != 0) { + kmem_free(aes_gcm_params, total_param_len); + out_mech->cm_param = NULL; + error = EFAULT; + goto out; + } + if (copyin((char *)STRUCT_FGETP(params, pAAD), + aes_gcm_params->pAAD, auth_data_len) != 0) { + kmem_free(aes_gcm_params, total_param_len); + out_mech->cm_param = NULL; + error = EFAULT; + goto out; + } + out_mech->cm_param = (char *)aes_gcm_params; + out_mech->cm_param_len = sizeof (CK_AES_GCM_PARAMS); + } +out: + *out_error = error; + return (rv); +} /* * Resource control checks don't need to be done. Why? Because this routine @@ -4594,6 +4685,10 @@ dprov_copyin_mechanism(crypto_provider_handle_t provider, rv = copyin_aes_ccm_mech(umech, kmech, &error, mode); goto out; + case AES_GCM_MECH_INFO_TYPE: + rv = copyin_aes_gcm_mech(umech, kmech, &error, mode); + goto out; + case DH_PKCS_DERIVE_MECH_INFO_TYPE: expected_param_len = param_len; break; @@ -4690,6 +4785,22 @@ dprov_free_mechanism(crypto_provider_handle_t provider, mech->cm_param = NULL; mech->cm_param_len = 0; } + return (CRYPTO_SUCCESS); + } + case AES_GCM_MECH_INFO_TYPE: { + CK_AES_GCM_PARAMS *params; + size_t total_param_len; + + if ((mech->cm_param != NULL) && (mech->cm_param_len != 0)) { + /* LINTED: pointer alignment */ + params = (CK_AES_GCM_PARAMS *)mech->cm_param; + total_param_len = mech->cm_param_len + + params->ulIvLen + params->ulAADLen; + kmem_free(params, total_param_len); + mech->cm_param = NULL; + mech->cm_param_len = 0; + } + return (CRYPTO_SUCCESS); } default: |