/* * p11test_case_pss_oaep.c: RSA-PSS and RSA-OAEP tests * * Copyright (C) 2017 Red Hat, Inc. * * Author: Jakub Jelen * * This library is free software; you can redistribute it and/or * modify it under the terms of the GNU Lesser General Public * License as published by the Free Software Foundation; either * version 2.1 of the License, or (at your option) any later version. * * This library is distributed in the hope that it will be useful, * but WITHOUT ANY WARRANTY; without even the implied warranty of * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU * Lesser General Public License for more details. * * You should have received a copy of the GNU General Public License * along with this program. If not, see . */ #include "p11test_case_pss_oaep.h" #include "libopensc/internal.h" #include #include #define SHORT_MESSAGE_TO_SIGN "Simple message for signing & verifying. It needs to be little bit longer to fit also longer keys and allow the truncation.\n" #define BUFFER_SIZE 4096 const unsigned char *global_message = (unsigned char *) SHORT_MESSAGE_TO_SIGN; size_t global_message_length = sizeof(SHORT_MESSAGE_TO_SIGN); const CK_MECHANISM_TYPE * get_oaep_mechanism_hashes(CK_MECHANISM_TYPE mech) { static CK_MECHANISM_TYPE h[6]; switch (mech) { case CKM_RSA_PKCS_OAEP: h[0] = CKM_SHA_1; h[1] = CKM_SHA224; h[2] = CKM_SHA256; h[3] = CKM_SHA384; h[4] = CKM_SHA512; h[5] = -1; break; default: h[0] = -1; break; } return h; } const CK_MECHANISM_TYPE * get_pss_mechanism_hashes(CK_MECHANISM_TYPE mech) { static CK_MECHANISM_TYPE h[6]; switch (mech) { case CKM_RSA_PKCS_PSS: h[0] = CKM_SHA_1; h[1] = CKM_SHA224; h[2] = CKM_SHA256; h[3] = CKM_SHA384; h[4] = CKM_SHA512; h[5] = -1; break; case CKM_SHA1_RSA_PKCS_PSS: h[0] = CKM_SHA_1; h[1] = -1; break; case CKM_SHA224_RSA_PKCS_PSS: h[0] = CKM_SHA224; h[1] = -1; break; case CKM_SHA256_RSA_PKCS_PSS: h[0] = CKM_SHA256; h[1] = -1; break; case CKM_SHA384_RSA_PKCS_PSS: h[0] = CKM_SHA384; h[1] = -1; break; case CKM_SHA512_RSA_PKCS_PSS: h[0] = CKM_SHA512; h[1] = -1; break; default: h[0] = -1; break; } return h; } const CK_MECHANISM_TYPE * get_mechanism_hashes(CK_MECHANISM_TYPE mech) { if (mech == CKM_RSA_PKCS_OAEP) return get_oaep_mechanism_hashes(mech); else return get_pss_mechanism_hashes(mech); } const CK_RSA_PKCS_MGF_TYPE * get_mgfs(void) { static CK_RSA_PKCS_MGF_TYPE h[6]; h[0] = CKG_MGF1_SHA1; h[1] = CKG_MGF1_SHA224; h[2] = CKG_MGF1_SHA256; h[3] = CKG_MGF1_SHA384; h[4] = CKG_MGF1_SHA512; h[5] = -1; return h; } const EVP_MD *mgf_cryptoki_to_ossl(CK_RSA_PKCS_MGF_TYPE mgf) { switch (mgf) { case CKG_MGF1_SHA224: return EVP_sha224(); case CKG_MGF1_SHA256: return EVP_sha256(); case CKG_MGF1_SHA384: return EVP_sha384(); case CKG_MGF1_SHA512: return EVP_sha512(); case CKG_MGF1_SHA1: default: return EVP_sha1(); } } const EVP_MD *md_cryptoki_to_ossl(CK_MECHANISM_TYPE hash) { /* Digest mechanisms */ switch (hash) { case CKM_SHA224: return EVP_sha224(); case CKM_SHA256: return EVP_sha256(); case CKM_SHA384: return EVP_sha384(); case CKM_SHA512: return EVP_sha512(); case CKM_SHA_1: default: return EVP_sha1(); } } size_t get_hash_length(CK_MECHANISM_TYPE mech) { switch (mech) { case CKM_SHA224: return SHA224_DIGEST_LENGTH; case CKM_SHA256: return SHA256_DIGEST_LENGTH; case CKM_SHA384: return SHA384_DIGEST_LENGTH; case CKM_SHA512: return SHA512_DIGEST_LENGTH; default: case CKM_SHA_1: return SHA_DIGEST_LENGTH; } } CK_BYTE *hash_message(const CK_BYTE *message, size_t message_length, CK_MECHANISM_TYPE hash) { switch (hash) { case CKM_SHA224: return SHA224(message, message_length, NULL); case CKM_SHA256: return SHA256(message, message_length, NULL); case CKM_SHA384: return SHA384(message, message_length, NULL); case CKM_SHA512: return SHA512(message, message_length, NULL); case CKM_SHA_1: default: return SHA1(message, message_length, NULL); } } int oaep_encrypt_message_openssl(test_cert_t *o, token_info_t *info, CK_BYTE *message, CK_ULONG message_length, test_mech_t *mech, unsigned char **enc_message) { size_t enc_length = 0; CK_RV rv = -1; EVP_PKEY_CTX *pctx = NULL; const EVP_MD *md = EVP_md_null(); const EVP_MD *mgf1_md = EVP_md_null(); EVP_PKEY *key = NULL; md = md_cryptoki_to_ossl(mech->hash); mgf1_md = mgf_cryptoki_to_ossl(mech->mgf); if ((key = EVP_PKEY_new()) == NULL || RSA_up_ref(o->key.rsa) < 1 || EVP_PKEY_set1_RSA(key, o->key.rsa) != 1) { fprintf(stderr, " [ ERROR %s ] Failed to initialize EVP_PKEY. Error: %s\n", o->id_str, ERR_error_string(ERR_peek_last_error(), NULL)); goto out; } if ((pctx = EVP_PKEY_CTX_new(key, NULL)) == NULL || EVP_PKEY_encrypt_init(pctx) != 1 || EVP_PKEY_CTX_set_rsa_padding(pctx, RSA_PKCS1_OAEP_PADDING) != 1 || EVP_PKEY_CTX_set_rsa_oaep_md(pctx, md) != 1 || EVP_PKEY_CTX_set_rsa_mgf1_md(pctx, mgf1_md) != 1) { fprintf(stderr, " [ ERROR %s ] Failed to initialize EVP_PKEY_CTX. Error: %s\n", o->id_str, ERR_error_string(ERR_peek_last_error(), NULL)); goto out; } if (EVP_PKEY_encrypt(pctx, NULL, &enc_length, message, message_length) <= 0) { fprintf(stderr, " [ ERROR %s ] Failed get signature length. Error: %s\n", o->id_str, ERR_error_string(ERR_peek_last_error(), NULL)); goto out; } *enc_message = OPENSSL_malloc(enc_length); rv = EVP_PKEY_encrypt(pctx, *enc_message, &enc_length, message, message_length); if (rv <= 0) { fprintf(stderr, " [ ERROR %s ] Signature is not valid. Error: %s\n", o->id_str, ERR_error_string(ERR_peek_last_error(), NULL)); } out: EVP_PKEY_CTX_free(pctx); EVP_PKEY_free(key); return enc_length; } void fill_oaep_params(CK_RSA_PKCS_OAEP_PARAMS *oaep_params, test_mech_t *mech) { oaep_params->hashAlg = mech->hash; oaep_params->mgf = mech->mgf; oaep_params->source = CKZ_DATA_SPECIFIED; oaep_params->pSourceData = NULL; oaep_params->ulSourceDataLen = 0; } int oaep_encrypt_message(test_cert_t *o, token_info_t *info, CK_BYTE *message, CK_ULONG message_length, test_mech_t *mech, unsigned char **enc_message) { CK_RV rv; CK_FUNCTION_LIST_PTR fp = info->function_pointer; CK_MECHANISM enc_mechanism = { mech->mech, NULL_PTR, 0 }; CK_RSA_PKCS_OAEP_PARAMS oaep_params; CK_ULONG enc_message_length; static int encrypt_support = 1; fill_oaep_params(&oaep_params, mech); enc_mechanism.pParameter = &oaep_params; enc_mechanism.ulParameterLen = sizeof(oaep_params); if (!encrypt_support) goto openssl_encrypt; rv = fp->C_EncryptInit(info->session_handle, &enc_mechanism, o->public_handle); if (rv != CKR_OK) { debug_print(" C_EncryptInit: rv = 0x%.8lX", rv); encrypt_support = 0; /* avoid trying over and over again */ goto openssl_encrypt; } /* get the expected length */ rv = fp->C_Encrypt(info->session_handle, message, message_length, NULL, &enc_message_length); if (rv != CKR_OK) { debug_print(" C_Encrypt: rv = 0x%.8lX", rv); goto openssl_encrypt; } *enc_message = malloc(enc_message_length); if (*enc_message == NULL) { debug_print("malloc returned null"); return -1; } /* Do the actual encryption with allocated buffer */ rv = fp->C_Encrypt(info->session_handle, message, message_length, *enc_message, &enc_message_length); if (rv == CKR_OK) { mech->result_flags |= FLAGS_DECRYPT_OPENSSL; return enc_message_length; } debug_print(" C_Encrypt: rv = 0x%.8lX", rv); openssl_encrypt: debug_print(" [ KEY %s ] Falling back to openssl encryption", o->id_str); return oaep_encrypt_message_openssl(o, info, message, message_length, mech, enc_message); } int oaep_decrypt_message(test_cert_t *o, token_info_t *info, CK_BYTE *enc_message, CK_ULONG enc_message_length, test_mech_t *mech, unsigned char **dec_message) { CK_RV rv; CK_FUNCTION_LIST_PTR fp = info->function_pointer; CK_MECHANISM dec_mechanism = { mech->mech, NULL_PTR, 0 }; CK_RSA_PKCS_OAEP_PARAMS oaep_params; CK_ULONG dec_message_length = BUFFER_SIZE; fill_oaep_params(&oaep_params, mech); dec_mechanism.pParameter = &oaep_params; dec_mechanism.ulParameterLen = sizeof(oaep_params); rv = fp->C_DecryptInit(info->session_handle, &dec_mechanism, o->private_handle); if (rv == CKR_KEY_TYPE_INCONSISTENT) { debug_print(" [SKIP %s ] Not allowed to decrypt with this key?", o->id_str); return 0; } else if (rv != CKR_OK) { debug_print(" C_DecryptInit: rv = 0x%.8lX\n", rv); return -1; } *dec_message = malloc(dec_message_length); always_authenticate(o, info); rv = fp->C_Decrypt(info->session_handle, enc_message, enc_message_length, *dec_message, &dec_message_length); if (rv != CKR_OK) { free(*dec_message); debug_print(" C_Decrypt: rv = 0x%.8lX\n", rv); return -1; } return (int) dec_message_length; } /* Perform encryption and decryption of a message using private key referenced * in the o object with mechanism defined by mech. * * NONE of the reasonable mechanisms support encryption/decryption * * Returns * * 1 for successful Encrypt&Decrypt sequence * * 0 for skipped test (unsupported mechanism, key, ...) * * -1 otherwise. * Serious errors terminate the execution. */ int oaep_encrypt_decrypt_test(test_cert_t *o, token_info_t *info, test_mech_t *mech) { CK_BYTE *message = (CK_BYTE *) SHORT_MESSAGE_TO_SIGN; CK_BYTE *dec_message = NULL; int dec_message_length = 0; int message_length = 16; unsigned char *enc_message = NULL; int enc_message_length, rv; if (o->private_handle == CK_INVALID_HANDLE) { debug_print(" [SKIP %s ] Missing private key", o->id_str); return 0; } if (o->type != EVP_PK_RSA) { debug_print(" [ KEY %s ] Skip non-RSA key for encryption", o->id_str); return 0; } if (mech->mech != CKM_RSA_PKCS_OAEP) { mech->usage_flags &= ~CKF_DECRYPT; debug_print(" [SKIP %s ] non RSA-OAEP mechanism", o->id_str); return 0; } message_length = MIN((int)global_message_length, (int)((o->bits+7)/8 - 2*get_hash_length(mech->hash) - 2)); /* will not work for 1024b RSA key and SHA512 hash: It has max size -2 */ if (message_length < 0) { mech->usage_flags &= ~CKF_DECRYPT; debug_print(" [SKIP %s ] Too small modulus (%ld bits)" " or too large hash %s (%lu B) for OAEP", o->id_str, o->bits, get_mechanism_name(mech->hash), get_hash_length(mech->hash)); return 0; } debug_print(" [ KEY %s ] Encrypt message of length %d using CKM_%s, " "hash CKM_%s, mgf=CKG_%s", o->id_str, (unsigned) message_length, get_mechanism_name(mech->mech), get_mechanism_name(mech->hash), get_mgf_name(mech->mgf)); enc_message_length = oaep_encrypt_message(o, info, message, (unsigned) message_length, mech, &enc_message); if (enc_message_length <= 0) { return -1; } debug_print(" [ KEY %s ] Decrypt message", o->id_str); dec_message_length = oaep_decrypt_message(o, info, enc_message, enc_message_length, mech, &dec_message); free(enc_message); if (dec_message_length <= 0) { return -1; } if (memcmp(dec_message, message, dec_message_length) == 0 && dec_message_length == message_length) { debug_print(" [ OK %s ] Text decrypted successfully.", o->id_str); mech->result_flags |= FLAGS_DECRYPT; rv = 1; } else { dec_message[dec_message_length] = '\0'; debug_print(" [ ERROR %s ] Text decryption failed. Recovered text: %s", o->id_str, dec_message); rv = 0; } free(dec_message); return rv; } static int get_max_salt_len(unsigned long bits, CK_MECHANISM_TYPE hash) { return (bits + 7)/8 - get_hash_length(hash) - 2; } int fill_pss_params(CK_RSA_PKCS_PSS_PARAMS *pss_params, test_mech_t *mech, test_cert_t *o) { pss_params->hashAlg = mech->hash; pss_params->mgf = mech->mgf; switch (mech->salt){ case -2: /* max possible ( modlen - hashlen -2 ) */ pss_params->sLen = get_max_salt_len(o->bits,mech->hash); break; case -1: /* digest length */ /* will not work with SHA512 and 1024b keys (max is 62b!) */ if ((int) get_hash_length(mech->hash) > get_max_salt_len(o->bits, mech->hash)) { return -1; } pss_params->sLen = get_hash_length(mech->hash); break; case 0: default: pss_params->sLen = 0; break; } return 1; } int pss_sign_message(test_cert_t *o, token_info_t *info, CK_BYTE *message, CK_ULONG message_length, test_mech_t *mech, unsigned char **sign) { CK_RV rv; CK_FUNCTION_LIST_PTR fp = info->function_pointer; CK_MECHANISM sign_mechanism = { mech->mech, NULL_PTR, 0 }; CK_ULONG sign_length = 0; CK_RSA_PKCS_PSS_PARAMS pss_params; if (fill_pss_params(&pss_params, mech, o) != 1) { debug_print(" [SKIP %s ] Impossible to use requested salt length", o->id_str); return 0; } sign_mechanism.pParameter = &pss_params; sign_mechanism.ulParameterLen = sizeof(pss_params); rv = fp->C_SignInit(info->session_handle, &sign_mechanism, o->private_handle); if (rv == CKR_KEY_TYPE_INCONSISTENT) { debug_print(" [SKIP %s ] Not allowed to sign with this key?", o->id_str); return 0; } else if (rv == CKR_MECHANISM_INVALID) { debug_print(" [SKIP %s ] Bad mechanism. Not supported?", o->id_str); return 0; } else if (rv != CKR_OK) { debug_print(" C_SignInit: rv = 0x%.8lX\n", rv); return -1; } always_authenticate(o, info); /* Call C_Sign with NULL argument to find out the real size of signature */ rv = fp->C_Sign(info->session_handle, message, message_length, *sign, &sign_length); if (rv != CKR_OK) { fprintf(stderr, " C_Sign: rv = 0x%.8lX\n", rv); return -1; } *sign = malloc(sign_length); if (*sign == NULL) { fprintf(stderr, "%s: malloc failed", __func__); return -1; } /* Call C_Sign with allocated buffer to the actual signature */ rv = fp->C_Sign(info->session_handle, message, message_length, *sign, &sign_length); if (rv != CKR_OK) { free(*sign); fprintf(stderr, " C_Sign: rv = 0x%.8lX\n", rv); return -1; } return sign_length; } int pss_verify_message_openssl(test_cert_t *o, token_info_t *info, CK_BYTE *message, CK_ULONG message_length, test_mech_t *mech, unsigned char *sign, CK_ULONG sign_length) { CK_RV rv = -1; EVP_PKEY_CTX *pctx = NULL; const CK_BYTE *my_message; CK_ULONG my_message_length; const EVP_MD *mgf_md = EVP_md_null(); const EVP_MD *md = EVP_md_null(); EVP_PKEY *key = NULL; md = md_cryptoki_to_ossl(mech->hash); mgf_md = mgf_cryptoki_to_ossl(mech->mgf); if (mech->mech != CKM_RSA_PKCS_PSS) { my_message = hash_message(message, message_length, mech->hash); my_message_length = get_hash_length(mech->hash); } else { my_message = message; my_message_length = message_length; } if ((key = EVP_PKEY_new()) == NULL || RSA_up_ref(o->key.rsa) < 1 || EVP_PKEY_set1_RSA(key, o->key.rsa) != 1) { fprintf(stderr, " [ ERROR %s ] Failed to initialize EVP_PKEY. Error: %s\n", o->id_str, ERR_error_string(ERR_peek_last_error(), NULL)); goto out; } if ((pctx = EVP_PKEY_CTX_new(key, NULL)) == NULL || EVP_PKEY_verify_init(pctx) != 1 || EVP_PKEY_CTX_set_rsa_padding(pctx, RSA_PKCS1_PSS_PADDING) != 1 || EVP_PKEY_CTX_set_signature_md(pctx, md) != 1 || EVP_PKEY_CTX_set_rsa_pss_saltlen(pctx, mech->salt) != 1 || EVP_PKEY_CTX_set_rsa_mgf1_md(pctx, mgf_md) != 1) { fprintf(stderr, " [ ERROR %s ] Failed to initialize EVP_PKEY_CTX. Error: %s\n", o->id_str, ERR_error_string(ERR_peek_last_error(), NULL)); goto out; } rv = EVP_PKEY_verify(pctx, sign, sign_length, my_message, my_message_length); if (rv == 1) { debug_print(" [ OK %s ] Signature is valid.", o->id_str); mech->result_flags |= FLAGS_SIGN_OPENSSL; } else { fprintf(stderr, " [ ERROR %s ] Signature is not valid. Error: %s\n", o->id_str, ERR_error_string(ERR_peek_last_error(), NULL)); goto out; } out: EVP_PKEY_CTX_free(pctx); EVP_PKEY_free(key); return rv; } int pss_verify_message(test_cert_t *o, token_info_t *info, CK_BYTE *message, CK_ULONG message_length, test_mech_t *mech, unsigned char *sign, CK_ULONG sign_length) { CK_RV rv; CK_FUNCTION_LIST_PTR fp = info->function_pointer; CK_MECHANISM sign_mechanism = { mech->mech, NULL_PTR, 0 }; CK_RSA_PKCS_PSS_PARAMS pss_params; static int verify_support = 1; if (!verify_support) goto openssl_verify; fill_pss_params(&pss_params, mech, o); sign_mechanism.pParameter = &pss_params; sign_mechanism.ulParameterLen = sizeof(pss_params); /* try C_Verify() if it is supported */ rv = fp->C_VerifyInit(info->session_handle, &sign_mechanism, o->public_handle); if (rv != CKR_OK) { debug_print(" C_VerifyInit: rv = 0x%.8lX", rv); verify_support = 0; /* avoid trying over and over again */ goto openssl_verify; } rv = fp->C_Verify(info->session_handle, message, message_length, sign, sign_length); if (rv == CKR_OK) { mech->result_flags |= FLAGS_SIGN; debug_print(" [ OK %s ] Verification successful", o->id_str); return 1; } debug_print(" C_Verify: rv = 0x%.8lX", rv); verify_support = 0; /* avoid trying over and over again */ openssl_verify: debug_print(" [ KEY %s ] Falling back to openssl verification", o->id_str); return pss_verify_message_openssl(o, info, message, message_length, mech, sign, sign_length); } /* Perform signature and verification of a message using private key referenced * in the o object with mechanism defined by mech. * * Returns * * 1 for successful Sign&Verify sequence * * 0 for skipped test (unsupported mechanism, key, ...) * * -1 otherwise. * Serious errors terminate the execution. */ int pss_sign_verify_test(test_cert_t *o, token_info_t *info, test_mech_t *mech) { CK_BYTE *message = NULL; size_t message_length = global_message_length; CK_BYTE *sign = NULL; CK_ULONG sign_length = 0; int rv = 0; if (o->private_handle == CK_INVALID_HANDLE) { debug_print(" [SKIP %s ] Missing private key", o->id_str); return 0; } if (o->type != EVP_PK_RSA) { debug_print(" [SKIP %s ] Skip non-RSA key", o->id_str); return 0; } if (!is_pss_mechanism(mech->mech)) { mech->usage_flags &= ~CKF_SIGN; debug_print(" [SKIP %s ] non RSA-PSS mechanism %s", o->id_str, get_mechanism_name(mech->mech)); return 0; } if (mech->mech == CKM_RSA_PKCS_PSS) { message = hash_message(global_message, global_message_length, mech->hash); message_length = get_hash_length(mech->hash); } else { message = (unsigned char *) SHORT_MESSAGE_TO_SIGN; } debug_print(" [ KEY %s ] Signing message using CKM_%s, CKM_%s," " CKG_%s, salt_len=%d", o->id_str, get_mechanism_name(mech->mech), get_mechanism_name(mech->hash), get_mgf_name(mech->mgf), mech->salt); rv = pss_sign_message(o, info, message, message_length, mech, &sign); if (rv <= 0) { return rv; } sign_length = (unsigned long) rv; debug_print(" [ KEY %s ] Verify message signature", o->id_str); rv = pss_verify_message(o, info, message, message_length, mech, sign, sign_length); free(sign); return rv; } /* ignore the prefilled mechanisms and list all combinations of mechanisms * found, all reasonable hash functions, MGFs and salt lengths */ void fill_object_pss_mechanisms(token_info_t *info, test_cert_t *o) { const CK_MECHANISM_TYPE *h; const CK_RSA_PKCS_MGF_TYPE *mgf; int n = 0, s; unsigned int j; for (j = 0; j < token.num_rsa_mechs; j++) { test_mech_t *source_mech = &token.rsa_mechs[j]; /* skip non-RSA-PSS mechs early */ if (!is_pss_mechanism(source_mech->mech) && source_mech->mech != CKM_RSA_PKCS_OAEP) { continue; } h = get_mechanism_hashes(source_mech->mech); for (; *h != (CK_MECHANISM_TYPE) -1; h++) { mgf = get_mgfs(); for (; *mgf != (CK_RSA_PKCS_MGF_TYPE) -1; mgf++) { /* OAEP does not have salt */ if (source_mech->mech == CKM_RSA_PKCS_OAEP) s = 0; else s = -2; for (; s <= 0; s++) { test_mech_t *mech = &o->mechs[n++]; mech->mech = source_mech->mech; mech->hash = *h; mech->mgf = *mgf; mech->salt = s; mech->usage_flags = source_mech->usage_flags; mech->result_flags = 0; if (n >= MAX_MECHS) P11TEST_FAIL(info, "Too many mechanisms (%d)", MAX_MECHS); } } } } o->num_mechs = n; } int have_pss_oaep_mechanisms() { unsigned have = 0, i; for (i = 0; i <= token.num_rsa_mechs; i++) { if (is_pss_mechanism(token.rsa_mechs[i].mech) || token.rsa_mechs[i].mech == CKM_RSA_PKCS_OAEP) { have++; } } return have; } void pss_oaep_test(void **state) { token_info_t *info = (token_info_t *) *state; unsigned int i; int used, j; test_certs_t objects; P11TEST_START(info); if (have_pss_oaep_mechanisms() == 0) { fprintf(stderr, "Token does not support any RSA-PSS or OAEP mechanisms. Skipping.\n"); skip(); } objects.count = 0; objects.data = NULL; search_for_all_objects(&objects, info); debug_print("\nCheck functionality of Sign&Verify and/or Encrypt&Decrypt"); for (i = 0; i < objects.count; i++) { test_cert_t *o = &objects.data[i]; /* do the Sign&Verify and/or Encrypt&Decrypt */ used = 0; if (o->private_handle == CK_INVALID_HANDLE) { debug_print(" [SKIP %s ] Missing private key", o->id_str); continue; } fill_object_pss_mechanisms(info, o); for (j = 0; j < o->num_mechs; j++) if (o->mechs[j].mech != CKM_RSA_PKCS_OAEP) used |= pss_sign_verify_test(o, info, &(o->mechs[j])); for (j = 0; j < o->num_mechs; j++) if (o->mechs[j].mech == CKM_RSA_PKCS_OAEP) used |= oaep_encrypt_decrypt_test(o, info, &(o->mechs[j])); if (!used) { debug_print(" [ WARN %s ] Private key with unknown purpose T:%02lX", o->id_str, o->key_type); } } if (objects.count == 0) { printf(" [WARN] No objects to display\n"); return; } /* print summary */ printf("[KEY ID] [LABEL]\n"); printf("[ TYPE ] [ SIZE ] [PUBLIC] [SIGN&VERIFY] [ENC&DECRYPT]\n"); printf("[ MECHANISM ] [ HASH ] [ MGF ] [SALT] [ WORKS ] [ WORKS ]\n"); P11TEST_DATA_ROW(info, 7, 's', "KEY ID", 's', "MECHANISM", 's', "HASH", 's', "MGF", 's', "SALT", 's', "SIGN&VERIFY WORKS", 's', "ENCRYPT&DECRYPT WORKS"); for (i = 0; i < objects.count; i++) { test_cert_t *o = &objects.data[i]; /* Do not go through incomplete pairs */ if (o->private_handle == CK_INVALID_HANDLE) continue; /* Do not list non-RSA keys here */ if (o->type != EVP_PK_RSA) continue; printf("\n[%-6s] [%s]\n", o->id_str, o->label); printf("[ %s ] [%6lu] [ %s ] [%s%s] [%s%s]\n", o->key_type == CKK_RSA ? "RSA " : o->key_type == CKK_EC ? " EC " : " ?? ", o->bits, o->verify_public == 1 ? " ./ " : " ", o->sign ? "[./] " : "[ ] ", o->verify ? " [./] " : " [ ] ", o->encrypt ? "[./] " : "[ ] ", o->decrypt ? " [./] " : " [ ] "); if (!o->sign && !o->verify && !o->encrypt && !o->decrypt) { printf(" no usable attributes found ... ignored\n"); continue; } for (j = 0; j < o->num_mechs; j++) { test_mech_t *mech = &o->mechs[j]; printf(" [ %-20s ] [%-6s] [%-11s] [%4d] [ %s ] [ %s ]\n", get_mechanism_name(mech->mech), get_mechanism_name(mech->hash), get_mgf_name(mech->mgf), mech->salt, mech->result_flags & FLAGS_SIGN_ANY ? "[./]" : " ", mech->result_flags & FLAGS_DECRYPT_ANY ? "[./]" : " "); if ((mech->result_flags & FLAGS_SIGN_ANY) == 0 && (mech->result_flags & FLAGS_DECRYPT_ANY) == 0) continue; /* skip empty rows for export */ P11TEST_DATA_ROW(info, 7, 's', o->id_str, 's', get_mechanism_name(mech->mech), 's', get_mechanism_name(mech->hash), 's', get_mgf_name(mech->mgf), 'd', mech->salt, 's', mech->result_flags & FLAGS_SIGN_ANY ? "YES" : "", 's', mech->result_flags & FLAGS_DECRYPT_ANY ? "YES" : ""); } } printf(" Public == Cert ----------^ ^ ^ ^ ^ ^ ^\n"); printf(" Sign Attribute -------------------------------------------' | | | | |\n"); printf(" Sign&Verify functionality -----------------------------------' | | | |\n"); printf(" Verify Attribute -----------------------------------------------' | | |\n"); printf(" Encrypt Attribute ------------------------------------------------------' | |\n"); printf(" Encrypt & Decrypt functionality -------------------------------------------' |\n"); printf(" Decrypt Attribute ------------------------------------------------------------'\n"); clean_all_objects(&objects); P11TEST_PASS(info); }