/* ==================================================================== * Copyright (c) 2011 The OpenSSL Project. All rights reserved. * * Redistribution and use in source and binary forms, with or without * modification, are permitted provided that the following conditions * are met: * * 1. Redistributions of source code must retain the above copyright * notice, this list of conditions and the following disclaimer. * * 2. Redistributions in binary form must reproduce the above copyright * notice, this list of conditions and the following disclaimer in * the documentation and/or other materials provided with the * distribution. * * 3. All advertising materials mentioning features or use of this * software must display the following acknowledgment: * "This product includes software developed by the OpenSSL Project * for use in the OpenSSL Toolkit. (http://www.openssl.org/)" * * 4. The names "OpenSSL Toolkit" and "OpenSSL Project" must not be used to * endorse or promote products derived from this software without * prior written permission. For written permission, please contact * openssl-core@openssl.org. * * 5. Products derived from this software may not be called "OpenSSL" * nor may "OpenSSL" appear in their names without prior written * permission of the OpenSSL Project. * * 6. Redistributions of any form whatsoever must retain the following * acknowledgment: * "This product includes software developed by the OpenSSL Project * for use in the OpenSSL Toolkit (http://www.openssl.org/)" * * THIS SOFTWARE IS PROVIDED BY THE OpenSSL PROJECT ``AS IS'' AND ANY * EXPRESSED OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR * PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE OpenSSL PROJECT OR * ITS CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, * SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT * NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; * LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, * STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) * ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED * OF THE POSSIBILITY OF SUCH DAMAGE. * */ #define OPENSSL_FIPSAPI #include #include #include #include #include #include #include #include #include #include #include #ifdef OPENSSL_FIPS /* Power on self test (POST) support functions */ #include #include "fips_locl.h" /* POST notification callback */ int (*fips_post_cb)(int op, int id, int subid, void *ex); void FIPS_post_set_callback( int (*post_cb)(int op, int id, int subid, void *ex)) { fips_post_cb = post_cb; } /* POST status: i.e. status of all tests */ #define FIPS_POST_STATUS_NOT_STARTED 0 #define FIPS_POST_STATUS_OK 1 #define FIPS_POST_STATUS_RUNNING 2 #define FIPS_POST_STATUS_FAILED -1 static int post_status = 0; /* Set to 1 if any test failed */ static int post_failure = 0; /* All tests started */ int fips_post_begin(void) { post_failure = 0; post_status = FIPS_POST_STATUS_NOT_STARTED; if (fips_post_cb) if (!fips_post_cb(FIPS_POST_BEGIN, 0, 0, NULL)) return 0; post_status = FIPS_POST_STATUS_RUNNING; return 1; } void fips_post_end(void) { if (post_failure) { post_status = FIPS_POST_STATUS_FAILED; fips_post_cb(FIPS_POST_END, 0, 0, NULL); } else { post_status = FIPS_POST_STATUS_OK; fips_post_cb(FIPS_POST_END, 1, 0, NULL); } } /* A self test started */ int fips_post_started(int id, int subid, void *ex) { if (fips_post_cb) return fips_post_cb(FIPS_POST_STARTED, id, subid, ex); return 1; } /* A self test passed successfully */ int fips_post_success(int id, int subid, void *ex) { if (fips_post_cb) return fips_post_cb(FIPS_POST_SUCCESS, id, subid, ex); return 1; } /* A self test failed */ int fips_post_failed(int id, int subid, void *ex) { post_failure = 1; if (fips_post_cb) return fips_post_cb(FIPS_POST_FAIL, id, subid, ex); return 1; } /* Indicate if a self test failure should be induced */ int fips_post_corrupt(int id, int subid, void *ex) { if (fips_post_cb) return fips_post_cb(FIPS_POST_CORRUPT, id, subid, ex); return 1; } /* Note: if selftests running return status OK so their operation is * not interrupted. This will only happen while selftests are actually * running so will not interfere with normal operation. */ int fips_post_status(void) { return post_status > 0 ? 1 : 0; } /* Run all selftests */ int FIPS_selftest(void) { int rv = 1; fips_post_begin(); if(!FIPS_check_incore_fingerprint()) rv = 0; if (!FIPS_selftest_drbg()) rv = 0; if (!FIPS_selftest_x931()) rv = 0; if (!FIPS_selftest_sha1()) rv = 0; if (!FIPS_selftest_hmac()) rv = 0; if (!FIPS_selftest_cmac()) rv = 0; if (!FIPS_selftest_aes()) rv = 0; if (!FIPS_selftest_aes_gcm()) rv = 0; if (!FIPS_selftest_des()) rv = 0; if (!FIPS_selftest_rsa()) rv = 0; if (!FIPS_selftest_ecdsa()) rv = 0; if (!FIPS_selftest_dsa()) rv = 0; fips_post_end(); return rv; } /* Generalized public key test routine. Signs and verifies the data * supplied in tbs using mesage digest md and setting RSA padding mode * pad_mode. If the 'kat' parameter is not NULL it will * additionally check the signature matches it: a known answer test * The string "fail_str" is used for identification purposes in case * of failure. If "pkey" is NULL just perform a message digest check. */ int fips_pkey_signature_test(int id, EVP_PKEY *pkey, const unsigned char *tbs, size_t tbslen, const unsigned char *kat, size_t katlen, const EVP_MD *digest, int pad_mode, const char *fail_str) { int subid; void *ex = NULL; int ret = 0; unsigned char *sig = NULL; unsigned int siglen; static const unsigned char str1[]="12345678901234567890"; DSA_SIG *dsig = NULL; ECDSA_SIG *esig = NULL; EVP_MD_CTX mctx; FIPS_md_ctx_init(&mctx); if (tbs == NULL) tbs = str1; if (tbslen == 0) tbslen = strlen((char *)tbs); if (digest == NULL) digest = EVP_sha256(); subid = M_EVP_MD_type(digest); if (!fips_post_started(id, subid, pkey)) return 1; if (!pkey || pkey->type == EVP_PKEY_RSA) { size_t sigsize; if (!pkey) sigsize = EVP_MAX_MD_SIZE; else sigsize = RSA_size(pkey->pkey.rsa); sig = OPENSSL_malloc(sigsize); if (!sig) { FIPSerr(FIPS_F_FIPS_PKEY_SIGNATURE_TEST,ERR_R_MALLOC_FAILURE); goto error; } } if (!FIPS_digestinit(&mctx, digest)) goto error; if (!FIPS_digestupdate(&mctx, tbs, tbslen)) goto error; if (!fips_post_corrupt(id, subid, pkey)) { if (!FIPS_digestupdate(&mctx, tbs, 1)) goto error; } if (pkey == NULL) { if (!FIPS_digestfinal(&mctx, sig, &siglen)) goto error; } else if (pkey->type == EVP_PKEY_RSA) { if (!FIPS_rsa_sign_ctx(pkey->pkey.rsa, &mctx, pad_mode, 0, NULL, sig, &siglen)) goto error; } else if (pkey->type == EVP_PKEY_DSA) { dsig = FIPS_dsa_sign_ctx(pkey->pkey.dsa, &mctx); if (!dsig) goto error; } else if (pkey->type == EVP_PKEY_EC) { esig = FIPS_ecdsa_sign_ctx(pkey->pkey.ec, &mctx); if (!esig) goto error; } if (kat && ((siglen != katlen) || memcmp(kat, sig, katlen))) goto error; #if 0 { /* Debug code to print out self test KAT discrepancies */ unsigned int i; fprintf(stderr, "%s=", fail_str); for (i = 0; i < siglen; i++) fprintf(stderr, "%02X", sig[i]); fprintf(stderr, "\n"); goto error; } #endif /* If just digest test we've finished */ if (pkey == NULL) { ret = 1; /* Well actually sucess as we've set ret to 1 */ goto error; } if (!FIPS_digestinit(&mctx, digest)) goto error; if (!FIPS_digestupdate(&mctx, tbs, tbslen)) goto error; if (pkey->type == EVP_PKEY_RSA) { ret = FIPS_rsa_verify_ctx(pkey->pkey.rsa, &mctx, pad_mode, 0, NULL, sig, siglen); } else if (pkey->type == EVP_PKEY_DSA) { ret = FIPS_dsa_verify_ctx(pkey->pkey.dsa, &mctx, dsig); } else if (pkey->type == EVP_PKEY_EC) { ret = FIPS_ecdsa_verify_ctx(pkey->pkey.ec, &mctx, esig); } error: if (dsig != NULL) FIPS_dsa_sig_free(dsig); if (esig != NULL) FIPS_ecdsa_sig_free(esig); if (sig) OPENSSL_free(sig); FIPS_md_ctx_cleanup(&mctx); if (ret != 1) { FIPSerr(FIPS_F_FIPS_PKEY_SIGNATURE_TEST,FIPS_R_TEST_FAILURE); if (fail_str) FIPS_add_error_data(2, "Type=", fail_str); fips_post_failed(id, subid, ex); return 0; } return fips_post_success(id, subid, pkey); } /* Generalized symmetric cipher test routine. Encrypt data, verify result * against known answer, decrypt and compare with original plaintext. */ int fips_cipher_test(int id, EVP_CIPHER_CTX *ctx, const EVP_CIPHER *cipher, const unsigned char *key, const unsigned char *iv, const unsigned char *plaintext, const unsigned char *ciphertext, int len) { unsigned char pltmp[FIPS_MAX_CIPHER_TEST_SIZE]; unsigned char citmp[FIPS_MAX_CIPHER_TEST_SIZE]; int subid = M_EVP_CIPHER_nid(cipher); int rv = 0; OPENSSL_assert(len <= FIPS_MAX_CIPHER_TEST_SIZE); memset(pltmp, 0, FIPS_MAX_CIPHER_TEST_SIZE); memset(citmp, 0, FIPS_MAX_CIPHER_TEST_SIZE); if (!fips_post_started(id, subid, NULL)) return 1; if (FIPS_cipherinit(ctx, cipher, key, iv, 1) <= 0) goto error; if (!FIPS_cipher(ctx, citmp, plaintext, len)) goto error; if (memcmp(citmp, ciphertext, len)) goto error; if (!fips_post_corrupt(id, subid, NULL)) citmp[0] ^= 0x1; if (FIPS_cipherinit(ctx, cipher, key, iv, 0) <= 0) goto error; FIPS_cipher(ctx, pltmp, citmp, len); if (memcmp(pltmp, plaintext, len)) goto error; rv = 1; error: if (rv == 0) { fips_post_failed(id, subid, NULL); return 0; } return fips_post_success(id, subid, NULL); } #endif