/* * CDDL HEADER START * * The contents of this file are subject to the terms of the * Common Development and Distribution License, Version 1.0 only * (the "License"). You may not use this file except in compliance * with the License. * * You can obtain a copy of the license at usr/src/OPENSOLARIS.LICENSE * or http://www.opensolaris.org/os/licensing. * See the License for the specific language governing permissions * and limitations under the License. * * When distributing Covered Code, include this CDDL HEADER in each * file and include the License file at usr/src/OPENSOLARIS.LICENSE. * If applicable, add the following below this CDDL HEADER, with the * fields enclosed by brackets "[]" replaced with your own identifying * information: Portions Copyright [yyyy] [name of copyright owner] * * CDDL HEADER END */ /* * Copyright 2004 Sun Microsystems, Inc. All rights reserved. * Use is subject to license terms. */ #pragma ident "%Z%%M% %I% %E% SMI" #include #include #include #include #include #include #include #include #include "softObject.h" #include "softOps.h" #include "softSession.h" #include "softMAC.h" /* * IPAD = 0x36 repeated 48 times for ssl md5, repeated 40 times for ssl sha1 * OPAD = 0x5C repeated 48 times for SSL md5, repeated 40 times for ssl sha1 */ const uint32_t md5_ssl_ipad[] = { 0x36363636, 0x36363636, 0x36363636, 0x36363636, 0x36363636, 0x36363636, 0x36363636, 0x36363636, 0x36363636, 0x36363636, 0x36363636, 0x36363636}; const uint32_t sha1_ssl_ipad[] = { 0x36363636, 0x36363636, 0x36363636, 0x36363636, 0x36363636, 0x36363636, 0x36363636, 0x36363636, 0x36363636, 0x36363636}; const uint32_t md5_ssl_opad[] = { 0x5c5c5c5c, 0x5c5c5c5c, 0x5c5c5c5c, 0x5c5c5c5c, 0x5c5c5c5c, 0x5c5c5c5c, 0x5c5c5c5c, 0x5c5c5c5c, 0x5c5c5c5c, 0x5c5c5c5c, 0x5c5c5c5c, 0x5c5c5c5c}; const uint32_t sha1_ssl_opad[] = { 0x5c5c5c5c, 0x5c5c5c5c, 0x5c5c5c5c, 0x5c5c5c5c, 0x5c5c5c5c, 0x5c5c5c5c, 0x5c5c5c5c, 0x5c5c5c5c, 0x5c5c5c5c, 0x5c5c5c5c}; /* * Allocate and initialize a HMAC context, and save the context pointer in * the session struct. For General-length HMAC, checks the length in the * parameter to see if it is in the right range. */ CK_RV soft_hmac_sign_verify_init_common(soft_session_t *session_p, CK_MECHANISM_PTR pMechanism, soft_object_t *key_p, boolean_t sign_op) { soft_hmac_ctx_t *hmac_ctx; CK_RV rv = CKR_OK; if ((key_p->class != CKO_SECRET_KEY) || (key_p->key_type != CKK_GENERIC_SECRET)) { return (CKR_KEY_TYPE_INCONSISTENT); } hmac_ctx = malloc(sizeof (soft_hmac_ctx_t)); if (hmac_ctx == NULL) { return (CKR_HOST_MEMORY); } switch (pMechanism->mechanism) { case CKM_SSL3_MD5_MAC: case CKM_SSL3_SHA1_MAC: case CKM_MD5_HMAC_GENERAL: case CKM_SHA_1_HMAC_GENERAL: if (pMechanism->ulParameterLen != sizeof (CK_MAC_GENERAL_PARAMS)) { free(hmac_ctx); return (CKR_MECHANISM_PARAM_INVALID); } if (pMechanism->mechanism == CKM_MD5_HMAC_GENERAL || pMechanism->mechanism == CKM_SSL3_MD5_MAC) { if (*(CK_MAC_GENERAL_PARAMS *)pMechanism->pParameter > MD5_HASH_SIZE) { free(hmac_ctx); return (CKR_MECHANISM_PARAM_INVALID); } } else { if (*(CK_MAC_GENERAL_PARAMS *)pMechanism->pParameter > SHA1_HASH_SIZE) { free(hmac_ctx); return (CKR_MECHANISM_PARAM_INVALID); } } hmac_ctx->hmac_len = *((CK_MAC_GENERAL_PARAMS_PTR) pMechanism->pParameter); /*FALLTHRU*/ case CKM_MD5_HMAC: case CKM_SHA_1_HMAC: if (pMechanism->mechanism == CKM_MD5_HMAC) { hmac_ctx->hmac_len = MD5_HASH_SIZE; } else if (pMechanism->mechanism == CKM_SHA_1_HMAC) { hmac_ctx->hmac_len = SHA1_HASH_SIZE; } /* Initialize a MAC context. */ rv = mac_init_ctx(session_p, key_p, hmac_ctx, pMechanism->mechanism); if (rv != CKR_OK) return (rv); (void) pthread_mutex_lock(&session_p->session_mutex); if (sign_op) { session_p->sign.mech.mechanism = pMechanism->mechanism; session_p->sign.context = hmac_ctx; } else { session_p->verify.mech.mechanism = pMechanism->mechanism; session_p->verify.context = hmac_ctx; } (void) pthread_mutex_unlock(&session_p->session_mutex); break; } return (CKR_OK); } /* * Initialize a HMAC context. */ CK_RV mac_init_ctx(soft_session_t *session_p, soft_object_t *key, soft_hmac_ctx_t *ctx, CK_MECHANISM_TYPE mech) { CK_RV rv = CKR_OK; switch (mech) { case CKM_SSL3_MD5_MAC: { CK_BYTE md5_ipad[MD5_SSL_PAD_AND_KEY_SIZE]; CK_BYTE md5_opad[MD5_SSL_PAD_AND_KEY_SIZE]; if (OBJ_SEC(key)->sk_value_len > MD5_SSL_PAD_AND_KEY_SIZE) { return (CKR_KEY_SIZE_RANGE); } bzero(md5_ipad, MD5_SSL_PAD_AND_KEY_SIZE); bzero(md5_opad, MD5_SSL_PAD_AND_KEY_SIZE); /* SSL MAC is HASH(key + opad + HASH(key + ipad + data)) */ (void) memcpy(md5_ipad, OBJ_SEC(key)->sk_value, OBJ_SEC(key)->sk_value_len); (void) memcpy(&md5_ipad[OBJ_SEC(key)->sk_value_len], md5_ssl_ipad, MD5_SSL_PAD_SIZE); (void) memcpy(md5_opad, OBJ_SEC(key)->sk_value, OBJ_SEC(key)->sk_value_len); (void) memcpy(&md5_opad[OBJ_SEC(key)->sk_value_len], md5_ssl_opad, MD5_SSL_PAD_SIZE); SOFT_MAC_INIT_CTX(MD5, &(ctx->hc_ctx_u.md5_ctx), md5_ipad, md5_opad, MD5_SSL_PAD_AND_KEY_SIZE); break; } case CKM_MD5_HMAC_GENERAL: case CKM_MD5_HMAC: { uint32_t md5_ipad[MD5_HMAC_INTS_PER_BLOCK]; uint32_t md5_opad[MD5_HMAC_INTS_PER_BLOCK]; CK_MECHANISM digest_mech; CK_ULONG hash_len = MD5_HASH_SIZE; bzero(md5_ipad, MD5_HMAC_BLOCK_SIZE); bzero(md5_opad, MD5_HMAC_BLOCK_SIZE); if (OBJ_SEC(key)->sk_value_len > MD5_HMAC_BLOCK_SIZE) { /* * Hash the key when it is longer than 64 bytes. */ digest_mech.mechanism = CKM_MD5; digest_mech.pParameter = NULL_PTR; digest_mech.ulParameterLen = 0; rv = soft_digest_init_internal(session_p, &digest_mech); if (rv != CKR_OK) return (rv); rv = soft_digest(session_p, OBJ_SEC(key)->sk_value, OBJ_SEC(key)->sk_value_len, (CK_BYTE_PTR)md5_ipad, &hash_len); session_p->digest.flags = 0; if (rv != CKR_OK) return (rv); (void) memcpy(md5_opad, md5_ipad, hash_len); } else { (void) memcpy(md5_ipad, OBJ_SEC(key)->sk_value, OBJ_SEC(key)->sk_value_len); (void) memcpy(md5_opad, OBJ_SEC(key)->sk_value, OBJ_SEC(key)->sk_value_len); } md5_hmac_ctx_init(&ctx->hc_ctx_u.md5_ctx, md5_ipad, md5_opad); break; } case CKM_SSL3_SHA1_MAC: { CK_BYTE sha1_ipad[SHA1_SSL_PAD_AND_KEY_SIZE]; CK_BYTE sha1_opad[SHA1_SSL_PAD_AND_KEY_SIZE]; if (OBJ_SEC(key)->sk_value_len > SHA1_HMAC_BLOCK_SIZE) { return (CKR_KEY_SIZE_RANGE); } bzero(sha1_ipad, SHA1_SSL_PAD_AND_KEY_SIZE); bzero(sha1_opad, SHA1_SSL_PAD_AND_KEY_SIZE); /* SSL MAC is HASH(key + opad + HASH(key + ipad + data)) */ (void) memcpy(sha1_ipad, OBJ_SEC(key)->sk_value, OBJ_SEC(key)->sk_value_len); (void) memcpy(&sha1_ipad[OBJ_SEC(key)->sk_value_len], sha1_ssl_ipad, SHA1_SSL_PAD_SIZE); (void) memcpy(sha1_opad, OBJ_SEC(key)->sk_value, OBJ_SEC(key)->sk_value_len); (void) memcpy(&sha1_opad[OBJ_SEC(key)->sk_value_len], sha1_ssl_opad, SHA1_SSL_PAD_SIZE); SOFT_MAC_INIT_CTX(SHA1, &(ctx->hc_ctx_u.sha1_ctx), sha1_ipad, sha1_opad, SHA1_SSL_PAD_AND_KEY_SIZE); break; } case CKM_SHA_1_HMAC_GENERAL: case CKM_SHA_1_HMAC: { uint32_t sha1_ipad[SHA1_HMAC_INTS_PER_BLOCK]; uint32_t sha1_opad[SHA1_HMAC_INTS_PER_BLOCK]; CK_MECHANISM digest_mech; CK_ULONG hash_len = SHA1_HASH_SIZE; bzero(sha1_ipad, SHA1_HMAC_BLOCK_SIZE); bzero(sha1_opad, SHA1_HMAC_BLOCK_SIZE); if (OBJ_SEC(key)->sk_value_len > SHA1_HMAC_BLOCK_SIZE) { /* * Hash the key when it is longer than 64 bytes. */ digest_mech.mechanism = CKM_SHA_1; digest_mech.pParameter = NULL_PTR; digest_mech.ulParameterLen = 0; rv = soft_digest_init_internal(session_p, &digest_mech); if (rv != CKR_OK) return (rv); rv = soft_digest(session_p, OBJ_SEC(key)->sk_value, OBJ_SEC(key)->sk_value_len, (CK_BYTE_PTR)sha1_ipad, &hash_len); session_p->digest.flags = 0; if (rv != CKR_OK) return (rv); (void) memcpy(sha1_opad, sha1_ipad, hash_len); } else { (void) memcpy(sha1_ipad, OBJ_SEC(key)->sk_value, OBJ_SEC(key)->sk_value_len); (void) memcpy(sha1_opad, OBJ_SEC(key)->sk_value, OBJ_SEC(key)->sk_value_len); } sha1_hmac_ctx_init(&ctx->hc_ctx_u.sha1_ctx, sha1_ipad, sha1_opad); break; } } return (rv); } /* * Called by soft_sign(), soft_sign_final(), soft_verify() or * soft_verify_final(). */ CK_RV soft_hmac_sign_verify_common(soft_session_t *session_p, CK_BYTE_PTR pData, CK_ULONG ulDataLen, CK_BYTE_PTR pSigned, CK_ULONG_PTR pulSignedLen, boolean_t sign_op) { soft_hmac_ctx_t *hmac_ctx; CK_MECHANISM_TYPE mechanism; #ifdef __sparcv9 /* LINTED */ uint_t datalen = (uint_t)ulDataLen; #else /* __sparcv9 */ uint_t datalen = ulDataLen; #endif /* __sparcv9 */ if (sign_op) { hmac_ctx = (soft_hmac_ctx_t *)session_p->sign.context; mechanism = session_p->sign.mech.mechanism; /* * If application asks for the length of the output buffer * to hold the signature? */ if (pSigned == NULL) { *pulSignedLen = hmac_ctx->hmac_len; return (CKR_OK); } /* Is the application-supplied buffer large enough? */ if (*pulSignedLen < hmac_ctx->hmac_len) { *pulSignedLen = hmac_ctx->hmac_len; return (CKR_BUFFER_TOO_SMALL); } } else { hmac_ctx = (soft_hmac_ctx_t *)session_p->verify.context; mechanism = session_p->verify.mech.mechanism; } switch (mechanism) { case CKM_SSL3_MD5_MAC: case CKM_MD5_HMAC_GENERAL: case CKM_MD5_HMAC: if (pData != NULL) { /* Called by soft_sign() or soft_verify(). */ SOFT_MAC_UPDATE(MD5, &(hmac_ctx->hc_ctx_u.md5_ctx), pData, datalen); } SOFT_MAC_FINAL(MD5, &(hmac_ctx->hc_ctx_u.md5_ctx), pSigned); *pulSignedLen = hmac_ctx->hmac_len; break; case CKM_SSL3_SHA1_MAC: case CKM_SHA_1_HMAC_GENERAL: case CKM_SHA_1_HMAC: if (pData != NULL) { /* Called by soft_sign() or soft_verify(). */ SOFT_MAC_UPDATE(SHA1, &(hmac_ctx->hc_ctx_u.sha1_ctx), pData, datalen); } SOFT_MAC_FINAL(SHA1, &(hmac_ctx->hc_ctx_u.sha1_ctx), pSigned); *pulSignedLen = hmac_ctx->hmac_len; break; } clean_exit: (void) pthread_mutex_lock(&session_p->session_mutex); if (sign_op) { bzero(session_p->sign.context, sizeof (soft_hmac_ctx_t)); free(session_p->sign.context); session_p->sign.context = NULL; } else { bzero(session_p->verify.context, sizeof (soft_hmac_ctx_t)); free(session_p->verify.context); session_p->verify.context = NULL; } (void) pthread_mutex_unlock(&session_p->session_mutex); return (CKR_OK); } /* * Called by soft_sign_update() or soft_verify_update(). */ CK_RV soft_hmac_sign_verify_update(soft_session_t *session_p, CK_BYTE_PTR pPart, CK_ULONG ulPartLen, boolean_t sign_op) { soft_hmac_ctx_t *hmac_ctx; CK_MECHANISM_TYPE mechanism; #ifdef __sparcv9 /* LINTED */ uint_t partlen = (uint_t)ulPartLen; #else /* __sparcv9 */ uint_t partlen = ulPartLen; #endif /* __sparcv9 */ if (sign_op) { hmac_ctx = (soft_hmac_ctx_t *)session_p->sign.context; mechanism = session_p->sign.mech.mechanism; } else { hmac_ctx = (soft_hmac_ctx_t *)session_p->verify.context; mechanism = session_p->verify.mech.mechanism; } switch (mechanism) { case CKM_SSL3_MD5_MAC: case CKM_MD5_HMAC_GENERAL: case CKM_MD5_HMAC: SOFT_MAC_UPDATE(MD5, &(hmac_ctx->hc_ctx_u.md5_ctx), pPart, partlen); break; case CKM_SSL3_SHA1_MAC: case CKM_SHA_1_HMAC_GENERAL: case CKM_SHA_1_HMAC: SOFT_MAC_UPDATE(SHA1, &(hmac_ctx->hc_ctx_u.sha1_ctx), pPart, partlen); break; } return (CKR_OK); } /* * The following 2 functions expect the MAC key to be alreay copied in * the ipad and opad */ void md5_hmac_ctx_init(md5_hc_ctx_t *md5_hmac_ctx, uint32_t *ipad, uint32_t *opad) { int i; /* XOR key with ipad (0x36) and opad (0x5c) */ for (i = 0; i < MD5_HMAC_INTS_PER_BLOCK; i++) { ipad[i] ^= 0x36363636; opad[i] ^= 0x5c5c5c5c; } SOFT_MAC_INIT_CTX(MD5, md5_hmac_ctx, ipad, opad, MD5_HMAC_BLOCK_SIZE); } void sha1_hmac_ctx_init(sha1_hc_ctx_t *sha1_hmac_ctx, uint32_t *ipad, uint32_t *opad) { int i; /* XOR key with ipad (0x36) and opad (0x5c) */ for (i = 0; i < SHA1_HMAC_INTS_PER_BLOCK; i++) { ipad[i] ^= 0x36363636; opad[i] ^= 0x5c5c5c5c; } SOFT_MAC_INIT_CTX(SHA1, sha1_hmac_ctx, (const uchar_t *)ipad, (const uchar_t *)opad, SHA1_HMAC_BLOCK_SIZE); }