* [including the GNU Public Licence.]
*/
+#define OPENSSL_FIPSAPI
+
#include <stdio.h>
#include <string.h>
#include <openssl/evp.h>
#include <openssl/err.h>
-#include <openssl/rand.h>
+#include <openssl/fips.h>
void FIPS_cipher_ctx_init(EVP_CIPHER_CTX *ctx)
{
return ctx;
}
+/* The purpose of these is to trap programs that attempt to use non FIPS
+ * algorithms in FIPS mode and ignore the errors.
+ */
+
+static int bad_init(EVP_CIPHER_CTX *ctx, const unsigned char *key,
+ const unsigned char *iv, int enc)
+ { FIPS_ERROR_IGNORED("Cipher init"); return 0;}
+
+static int bad_do_cipher(EVP_CIPHER_CTX *ctx, unsigned char *out,
+ const unsigned char *in, size_t inl)
+ { FIPS_ERROR_IGNORED("Cipher update"); return 0;}
+
+/* NB: no cleanup because it is allowed after failed init */
+
+static int bad_set_asn1(EVP_CIPHER_CTX *ctx, ASN1_TYPE *typ)
+ { FIPS_ERROR_IGNORED("Cipher set_asn1"); return 0;}
+static int bad_get_asn1(EVP_CIPHER_CTX *ctx, ASN1_TYPE *typ)
+ { FIPS_ERROR_IGNORED("Cipher get_asn1"); return 0;}
+static int bad_ctrl(EVP_CIPHER_CTX *ctx, int type, int arg, void *ptr)
+ { FIPS_ERROR_IGNORED("Cipher ctrl"); return 0;}
+
+static const EVP_CIPHER bad_cipher =
+ {
+ 0,
+ 1,
+ 0,
+ 0,
+ 0,
+ bad_init,
+ bad_do_cipher,
+ NULL,
+ 0,
+ bad_set_asn1,
+ bad_get_asn1,
+ bad_ctrl,
+ NULL
+ };
+
int FIPS_cipherinit(EVP_CIPHER_CTX *ctx, const EVP_CIPHER *cipher,
const unsigned char *key, const unsigned char *iv, int enc)
{
+ if(FIPS_selftest_failed())
+ {
+ FIPSerr(FIPS_F_FIPS_CIPHERINIT,FIPS_R_FIPS_SELFTEST_FAILED);
+ ctx->cipher = &bad_cipher;
+ return 0;
+ }
if (enc == -1)
enc = ctx->encrypt;
else
}
if (cipher)
{
+ /* Only FIPS ciphers allowed */
+ if (FIPS_module_mode() && !(cipher->flags & EVP_CIPH_FLAG_FIPS) &&
+ !(ctx->flags & EVP_CIPH_FLAG_NON_FIPS_ALLOW))
+ {
+ EVPerr(EVP_F_FIPS_CIPHERINIT, EVP_R_DISABLED_FOR_FIPS);
+ ctx->cipher = &bad_cipher;
+ return 0;
+ }
/* Ensure a context left lying around from last time is cleared
* (the previous check attempted to avoid this if the same
* ENGINE and EVP_CIPHER could be used). */
ctx->cipher_data=OPENSSL_malloc(ctx->cipher->ctx_size);
if (!ctx->cipher_data)
{
- EVPerr(EVP_F_EVP_CIPHERINIT_EX, ERR_R_MALLOC_FAILURE);
+ EVPerr(EVP_F_FIPS_CIPHERINIT, ERR_R_MALLOC_FAILURE);
return 0;
}
}
{
if(!FIPS_cipher_ctx_ctrl(ctx, EVP_CTRL_INIT, 0, NULL))
{
- EVPerr(EVP_F_EVP_CIPHERINIT_EX, EVP_R_INITIALIZATION_ERROR);
+ EVPerr(EVP_F_FIPS_CIPHERINIT, EVP_R_INITIALIZATION_ERROR);
return 0;
}
}
}
else if(!ctx->cipher)
{
- EVPerr(EVP_F_EVP_CIPHERINIT_EX, EVP_R_NO_CIPHER_SET);
+ EVPerr(EVP_F_FIPS_CIPHERINIT, EVP_R_NO_CIPHER_SET);
return 0;
}
/* we assume block size is a power of 2 in *cryptUpdate */
int FIPS_cipher_ctx_ctrl(EVP_CIPHER_CTX *ctx, int type, int arg, void *ptr)
{
int ret;
+ if (FIPS_selftest_failed())
+ {
+ FIPSerr(FIPS_F_FIPS_CIPHER_CTX_CTRL, FIPS_R_SELFTEST_FAILED);
+ return 0;
+ }
if(!ctx->cipher) {
- EVPerr(EVP_F_EVP_CIPHER_CTX_CTRL, EVP_R_NO_CIPHER_SET);
+ EVPerr(EVP_F_FIPS_CIPHER_CTX_CTRL, EVP_R_NO_CIPHER_SET);
return 0;
}
if(!ctx->cipher->ctrl) {
- EVPerr(EVP_F_EVP_CIPHER_CTX_CTRL, EVP_R_CTRL_NOT_IMPLEMENTED);
+ EVPerr(EVP_F_FIPS_CIPHER_CTX_CTRL, EVP_R_CTRL_NOT_IMPLEMENTED);
return 0;
}
ret = ctx->cipher->ctrl(ctx, type, arg, ptr);
if(ret == -1) {
- EVPerr(EVP_F_EVP_CIPHER_CTX_CTRL, EVP_R_CTRL_OPERATION_NOT_IMPLEMENTED);
+ EVPerr(EVP_F_FIPS_CIPHER_CTX_CTRL, EVP_R_CTRL_OPERATION_NOT_IMPLEMENTED);
return 0;
}
return ret;
}
+int FIPS_cipher_ctx_copy(EVP_CIPHER_CTX *out, const EVP_CIPHER_CTX *in)
+ {
+ if ((in == NULL) || (in->cipher == NULL))
+ {
+ EVPerr(EVP_F_FIPS_CIPHER_CTX_COPY,EVP_R_INPUT_NOT_INITIALIZED);
+ return 0;
+ }
+
+ /* Only FIPS ciphers allowed */
+ if (FIPS_module_mode() && !(in->cipher->flags & EVP_CIPH_FLAG_FIPS) &&
+ !(out->flags & EVP_CIPH_FLAG_NON_FIPS_ALLOW))
+ {
+ EVPerr(EVP_F_FIPS_CIPHER_CTX_COPY, EVP_R_DISABLED_FOR_FIPS);
+ out->cipher = &bad_cipher;
+ return 0;
+ }
+
+ FIPS_cipher_ctx_cleanup(out);
+ memcpy(out,in,sizeof *out);
+
+ if (in->cipher_data && in->cipher->ctx_size)
+ {
+ out->cipher_data=OPENSSL_malloc(in->cipher->ctx_size);
+ if (!out->cipher_data)
+ {
+ EVPerr(EVP_F_FIPS_CIPHER_CTX_COPY,ERR_R_MALLOC_FAILURE);
+ return 0;
+ }
+ memcpy(out->cipher_data,in->cipher_data,in->cipher->ctx_size);
+ }
+
+ if (in->cipher->flags & EVP_CIPH_CUSTOM_COPY)
+ return in->cipher->ctrl((EVP_CIPHER_CTX *)in, EVP_CTRL_COPY, 0, out);
+ return 1;
+ }
+
+/* You can't really set the key length with FIPS, so just check that the
+ caller sets the length the context already has. */
+int FIPS_cipher_ctx_set_key_length(EVP_CIPHER_CTX *ctx, int keylen)
+ {
+ if (ctx->key_len == keylen)
+ return 1;
+
+ EVPerr(EVP_F_FIPS_CIPHER_CTX_SET_KEY_LENGTH,EVP_R_INVALID_KEY_LENGTH);
+ return 0;
+ }
+
+
int FIPS_cipher(EVP_CIPHER_CTX *ctx, unsigned char *out,
const unsigned char *in, unsigned int inl)
{
+ if (FIPS_selftest_failed())
+ {
+ FIPSerr(FIPS_F_FIPS_CIPHER, FIPS_R_SELFTEST_FAILED);
+ return -1;
+ }
return ctx->cipher->do_cipher(ctx,out,in,inl);
}
+
+const EVP_CIPHER *FIPS_get_cipherbynid(int nid)
+ {
+ switch (nid)
+ {
+ case NID_aes_128_cbc:
+ return FIPS_evp_aes_128_cbc();
+
+ case NID_aes_128_ccm:
+ return FIPS_evp_aes_128_ccm();
+
+ case NID_aes_128_cfb1:
+ return FIPS_evp_aes_128_cfb1();
+
+ case NID_aes_128_cfb128:
+ return FIPS_evp_aes_128_cfb128();
+
+ case NID_aes_128_cfb8:
+ return FIPS_evp_aes_128_cfb8();
+
+ case NID_aes_128_ctr:
+ return FIPS_evp_aes_128_ctr();
+
+ case NID_aes_128_ecb:
+ return FIPS_evp_aes_128_ecb();
+
+ case NID_aes_128_gcm:
+ return FIPS_evp_aes_128_gcm();
+
+ case NID_aes_128_ofb128:
+ return FIPS_evp_aes_128_ofb();
+
+ case NID_aes_128_xts:
+ return FIPS_evp_aes_128_xts();
+
+ case NID_aes_192_cbc:
+ return FIPS_evp_aes_192_cbc();
+
+ case NID_aes_192_ccm:
+ return FIPS_evp_aes_192_ccm();
+
+ case NID_aes_192_cfb1:
+ return FIPS_evp_aes_192_cfb1();
+
+ case NID_aes_192_cfb128:
+ return FIPS_evp_aes_192_cfb128();
+
+ case NID_aes_192_cfb8:
+ return FIPS_evp_aes_192_cfb8();
+
+ case NID_aes_192_ctr:
+ return FIPS_evp_aes_192_ctr();
+
+ case NID_aes_192_ecb:
+ return FIPS_evp_aes_192_ecb();
+
+ case NID_aes_192_gcm:
+ return FIPS_evp_aes_192_gcm();
+
+ case NID_aes_192_ofb128:
+ return FIPS_evp_aes_192_ofb();
+
+ case NID_aes_256_cbc:
+ return FIPS_evp_aes_256_cbc();
+
+ case NID_aes_256_ccm:
+ return FIPS_evp_aes_256_ccm();
+
+ case NID_aes_256_cfb1:
+ return FIPS_evp_aes_256_cfb1();
+
+ case NID_aes_256_cfb128:
+ return FIPS_evp_aes_256_cfb128();
+
+ case NID_aes_256_cfb8:
+ return FIPS_evp_aes_256_cfb8();
+
+ case NID_aes_256_ctr:
+ return FIPS_evp_aes_256_ctr();
+
+ case NID_aes_256_ecb:
+ return FIPS_evp_aes_256_ecb();
+
+ case NID_aes_256_gcm:
+ return FIPS_evp_aes_256_gcm();
+
+ case NID_aes_256_ofb128:
+ return FIPS_evp_aes_256_ofb();
+
+ case NID_aes_256_xts:
+ return FIPS_evp_aes_256_xts();
+
+ case NID_des_ede_ecb:
+ return FIPS_evp_des_ede();
+
+ case NID_des_ede3_ecb:
+ return FIPS_evp_des_ede3();
+
+ case NID_des_ede3_cbc:
+ return FIPS_evp_des_ede3_cbc();
+
+ case NID_des_ede3_cfb1:
+ return FIPS_evp_des_ede3_cfb1();
+
+ case NID_des_ede3_cfb64:
+ return FIPS_evp_des_ede3_cfb64();
+
+ case NID_des_ede3_cfb8:
+ return FIPS_evp_des_ede3_cfb8();
+
+ case NID_des_ede3_ofb64:
+ return FIPS_evp_des_ede3_ofb();
+
+ case NID_des_ede_cbc:
+ return FIPS_evp_des_ede_cbc();
+
+ case NID_des_ede_cfb64:
+ return FIPS_evp_des_ede_cfb64();
+
+ case NID_des_ede_ofb64:
+ return FIPS_evp_des_ede_ofb();
+
+ default:
+ return NULL;
+
+ }
+ }
+