Experimental HMAC support via EVP_PKEY_METHOD.
authorDr. Stephen Henson <steve@openssl.org>
Wed, 11 Apr 2007 12:33:06 +0000 (12:33 +0000)
committerDr. Stephen Henson <steve@openssl.org>
Wed, 11 Apr 2007 12:33:06 +0000 (12:33 +0000)
17 files changed:
crypto/asn1/ameth_lib.c
crypto/err/err.c
crypto/err/err.h
crypto/err/openssl.ec
crypto/evp/digest.c
crypto/evp/evp.h
crypto/evp/m_sigver.c
crypto/evp/pmeth_lib.c
crypto/hmac/Makefile
crypto/hmac/hm_ameth.c [new file with mode: 0644]
crypto/hmac/hm_pmeth.c [new file with mode: 0644]
crypto/hmac/hmac.c
crypto/hmac/hmac.h
crypto/objects/obj_dat.h
crypto/objects/obj_mac.h
crypto/objects/obj_mac.num
crypto/objects/objects.txt

index 5a3132a..92e8d59 100644 (file)
@@ -68,6 +68,7 @@ extern const EVP_PKEY_ASN1_METHOD rsa_asn1_meths[];
 extern const EVP_PKEY_ASN1_METHOD dsa_asn1_meths[];
 extern const EVP_PKEY_ASN1_METHOD dh_asn1_meth;
 extern const EVP_PKEY_ASN1_METHOD eckey_asn1_meth;
+extern const EVP_PKEY_ASN1_METHOD hmac_asn1_meth;
 
 /* Keep this sorted in type order !! */
 static const EVP_PKEY_ASN1_METHOD *standard_methods[] = 
@@ -87,8 +88,9 @@ static const EVP_PKEY_ASN1_METHOD *standard_methods[] =
        &dsa_asn1_meths[4],
 #endif
 #ifndef OPENSSL_NO_EC
-       &eckey_asn1_meth
+       &eckey_asn1_meth,
 #endif
+       &hmac_asn1_meth
        };
 
 typedef int sk_cmp_fn_type(const char * const *a, const char * const *b);
index 6812a9a..acf16d9 100644 (file)
@@ -150,6 +150,7 @@ static ERR_STRING_DATA ERR_str_libraries[]=
 {ERR_PACK(ERR_LIB_TS,0,0)              ,"time stamp routines"},
 {ERR_PACK(ERR_LIB_ENGINE,0,0)          ,"engine routines"},
 {ERR_PACK(ERR_LIB_OCSP,0,0)            ,"OCSP routines"},
+{ERR_PACK(ERR_LIB_HMAC,0,0)            ,"HMAC routines"},
 {0,NULL},
        };
 
index 3e3d395..17e4909 100644 (file)
@@ -195,6 +195,7 @@ typedef struct err_state_st
 #define ERR_LIB_ECDH           43
 #define ERR_LIB_STORE           44
 #define ERR_LIB_TS             45
+#define ERR_LIB_HMAC           46
 
 #define ERR_LIB_USER           128
 
@@ -227,6 +228,7 @@ typedef struct err_state_st
 #define ECDHerr(f,r)  ERR_PUT_error(ERR_LIB_ECDH,(f),(r),__FILE__,__LINE__)
 #define STOREerr(f,r) ERR_PUT_error(ERR_LIB_STORE,(f),(r),__FILE__,__LINE__)
 #define TSerr(f,r) ERR_PUT_error(ERR_LIB_TS,(f),(r),__FILE__,__LINE__)
+#define HMACerr(f,r) ERR_PUT_error(ERR_LIB_HMAC,(f),(r),__FILE__,__LINE__)
 
 /* Borland C seems too stupid to be able to shift and do longs in
  * the pre-processor :-( */
index 1dc5b56..fed3d39 100644 (file)
@@ -32,6 +32,7 @@ L ECDSA               crypto/ecdsa/ecdsa.h            crypto/ecdsa/ecs_err.c
 L ECDH         crypto/ecdh/ecdh.h              crypto/ecdh/ech_err.c
 L STORE                crypto/store/store.h            crypto/store/str_err.c
 L TS           crypto/ts/ts.h                  crypto/ts/ts_err.c
+L HMAC         crypto/hmac/hmac.h              crypto/hmac/hmac_err.c
 
 # additional header files to be scanned for function names
 L NONE         crypto/x509/x509_vfy.h          NONE
index 256efd6..095774b 100644 (file)
@@ -198,19 +198,32 @@ int EVP_DigestInit_ex(EVP_MD_CTX *ctx, const EVP_MD *type, ENGINE *impl)
                if (ctx->digest && ctx->digest->ctx_size)
                        OPENSSL_free(ctx->md_data);
                ctx->digest=type;
-               if (type->ctx_size)
+               if (!(ctx->flags & EVP_MD_CTX_FLAG_NO_INIT) && type->ctx_size)
+                       {
+                       ctx->update = type->update;
                        ctx->md_data=OPENSSL_malloc(type->ctx_size);
+                       }
                }
 #ifndef OPENSSL_NO_ENGINE
 skip_to_init:
 #endif
+       if (ctx->pctx)
+               {
+               int r;
+               r = EVP_PKEY_CTX_ctrl(ctx->pctx, -1, EVP_PKEY_OP_TYPE_SIG,
+                                       EVP_PKEY_CTRL_DIGESTINIT, 0, ctx);
+               if (r <= 0 && (r != -2))
+                       return 0;
+               }
+       if (ctx->flags & EVP_MD_CTX_FLAG_NO_INIT)
+               return 1;
        return ctx->digest->init(ctx);
        }
 
 int EVP_DigestUpdate(EVP_MD_CTX *ctx, const void *data,
             size_t count)
        {
-       return ctx->digest->update(ctx,data,count);
+       return ctx->update(ctx,data,count);
        }
 
 /* The caller can assume that this removes any secret data from the context */
@@ -272,7 +285,7 @@ int EVP_MD_CTX_copy_ex(EVP_MD_CTX *out, const EVP_MD_CTX *in)
        EVP_MD_CTX_cleanup(out);
        memcpy(out,in,sizeof *out);
 
-       if (out->digest->ctx_size)
+       if (in->md_data && out->digest->ctx_size)
                {
                if (tmp_buf) out->md_data = tmp_buf;
                else out->md_data=OPENSSL_malloc(out->digest->ctx_size);
index 8a7218f..b2fb2a6 100644 (file)
 #define EVP_PKEY_DSA4  NID_dsaWithSHA1_2
 #define EVP_PKEY_DH    NID_dhKeyAgreement
 #define EVP_PKEY_EC    NID_X9_62_id_ecPublicKey
+#define EVP_PKEY_HMAC  NID_hmac
 
 #ifdef __cplusplus
 extern "C" {
@@ -266,6 +267,8 @@ struct env_md_ctx_st
        void *md_data;
        /* Public key context for sign/verify */
        EVP_PKEY_CTX *pctx;
+       /* Update function: usually copied from EVP_MD */
+       int (*update)(EVP_MD_CTX *ctx,const void *data,size_t count);
        } /* EVP_MD_CTX */;
 
 /* values for EVP_MD_CTX flags */
@@ -276,6 +279,7 @@ struct env_md_ctx_st
                                                * cleaned */
 #define EVP_MD_CTX_FLAG_REUSE          0x0004 /* Don't free up ctx->md_data
                                                * in EVP_MD_CTX_cleanup */
+#define EVP_MD_CTX_FLAG_NO_INIT                0x0008 /* Don't initialized md_data */
 
 /* MD operational flags */
 
@@ -997,6 +1001,10 @@ void EVP_PKEY_asn1_set_ctrl(EVP_PKEY_ASN1_METHOD *ameth,
 
 #define EVP_PKEY_CTRL_PKCS7_SIGN       5
 
+#define EVP_PKEY_CTRL_SET_MAC_KEY      6
+
+#define EVP_PKEY_CTRL_DIGESTINIT       7
+
 #define EVP_PKEY_ALG_CTRL              0x1000
 
 #define EVP_PKEY_FLAG_AUTOARGLEN       2
index 6ab7190..8fdfe61 100644 (file)
@@ -67,7 +67,6 @@ static int do_sigver_init(EVP_MD_CTX *ctx, EVP_PKEY_CTX **pctx,
                          const EVP_MD *type, ENGINE *e, EVP_PKEY *pkey,
                          int ver)
        {
-       int r = 0;
        if (ctx->pctx == NULL)
                ctx->pctx = EVP_PKEY_CTX_new(pkey, e);
        if (ctx->pctx == NULL)
@@ -76,9 +75,9 @@ static int do_sigver_init(EVP_MD_CTX *ctx, EVP_PKEY_CTX **pctx,
                {
                if (ctx->pctx->pmeth->verifyctx_init)
                        {
-                       r = ctx->pctx->pmeth->verifyctx_init(ctx->pctx, ctx);
-                       if (r <= 0)
+                       if (ctx->pctx->pmeth->verifyctx_init(ctx->pctx, ctx) <=0)
                                return 0;
+                       ctx->pctx->operation = EVP_PKEY_OP_VERIFYCTX;
                        }
                else if (EVP_PKEY_verify_init(ctx->pctx) <= 0)
                        return 0;
@@ -87,18 +86,18 @@ static int do_sigver_init(EVP_MD_CTX *ctx, EVP_PKEY_CTX **pctx,
                {
                if (ctx->pctx->pmeth->signctx_init)
                        {
-                       r = ctx->pctx->pmeth->signctx_init(ctx->pctx, ctx);
-                       if (r <= 0)
+                       if (ctx->pctx->pmeth->signctx_init(ctx->pctx, ctx) <= 0)
                                return 0;
+                       ctx->pctx->operation = EVP_PKEY_OP_SIGNCTX;
                        }
-               if (EVP_PKEY_sign_init(ctx->pctx) <= 0)
+               else if (EVP_PKEY_sign_init(ctx->pctx) <= 0)
                        return 0;
                }
        if (EVP_PKEY_CTX_set_signature_md(ctx->pctx, type) <= 0)
                return 0;
        if (pctx)
                *pctx = ctx->pctx;
-       if ((r != 2) && !EVP_DigestInit_ex(ctx, type, e))
+       if (!EVP_DigestInit_ex(ctx, type, e))
                return 0;
        return 1;
        }
@@ -118,7 +117,11 @@ int EVP_DigestVerifyInit(EVP_MD_CTX *ctx, EVP_PKEY_CTX **pctx,
 
 int EVP_DigestSignFinal(EVP_MD_CTX *ctx, unsigned char *sigret, size_t *siglen)
        {
-       int r;
+       int sctx, r = 0;
+       if (ctx->pctx->pmeth->signctx)
+               sctx = 1;
+       else
+               sctx = 0;
        if (sigret)
                {
                MS_STATIC EVP_MD_CTX tmp_ctx;
@@ -127,20 +130,26 @@ int EVP_DigestSignFinal(EVP_MD_CTX *ctx, unsigned char *sigret, size_t *siglen)
                EVP_MD_CTX_init(&tmp_ctx);
                if (!EVP_MD_CTX_copy_ex(&tmp_ctx,ctx))
                        return 0;
-               if (tmp_ctx.pctx->pmeth->signctx)
+               if (sctx)
                        r = tmp_ctx.pctx->pmeth->signctx(tmp_ctx.pctx,
                                        sigret, siglen, &tmp_ctx);
                else
                        r = EVP_DigestFinal_ex(&tmp_ctx,md,&mdlen);
                EVP_MD_CTX_cleanup(&tmp_ctx);
-               if (!r)
-                       return 0;
+               if (sctx || !r)
+                       return r;
                if (EVP_PKEY_sign(ctx->pctx, sigret, siglen, md, mdlen) <= 0)
                        return 0;
                }
        else
                {
-               if (EVP_PKEY_sign(ctx->pctx, sigret, siglen, NULL,
+               if (sctx)
+                       {
+                       if (ctx->pctx->pmeth->signctx(ctx->pctx, 
+                                               sigret, siglen, ctx) <= 0)
+                               return 0;
+                       }
+               else if (EVP_PKEY_sign(ctx->pctx, sigret, siglen, NULL,
                                                EVP_MD_size(ctx->digest)) <= 0)
                        return 0;
                }
@@ -153,10 +162,15 @@ int EVP_DigestVerifyFinal(EVP_MD_CTX *ctx, unsigned char *sig, size_t siglen)
        unsigned char md[EVP_MAX_MD_SIZE];
        int r;
        unsigned int mdlen;
+       int vctx;
+       if (ctx->pctx->pmeth->signctx)
+               vctx = 1;
+       else
+               vctx = 0;
        EVP_MD_CTX_init(&tmp_ctx);
        if (!EVP_MD_CTX_copy_ex(&tmp_ctx,ctx))
                return -1;      
-       if (tmp_ctx.pctx->pmeth->verifyctx)
+       if (vctx)
                {
                r = tmp_ctx.pctx->pmeth->verifyctx(tmp_ctx.pctx,
                                        sig, siglen, &tmp_ctx);
@@ -164,7 +178,7 @@ int EVP_DigestVerifyFinal(EVP_MD_CTX *ctx, unsigned char *sig, size_t siglen)
        else
                r = EVP_DigestFinal_ex(&tmp_ctx,md,&mdlen);
        EVP_MD_CTX_cleanup(&tmp_ctx);
-       if (!r)
-               return -1;
+       if (vctx || !r)
+               return r;
        return EVP_PKEY_verify(ctx->pctx, sig, siglen, md, mdlen);
        }
index 500aad9..6abb951 100644 (file)
 typedef int sk_cmp_fn_type(const char * const *a, const char * const *b);
 STACK *app_pkey_methods = NULL;
 
-extern EVP_PKEY_METHOD rsa_pkey_meth, dh_pkey_meth, dsa_pkey_meth, ec_pkey_meth;
+extern const EVP_PKEY_METHOD rsa_pkey_meth, dh_pkey_meth, dsa_pkey_meth;
+extern const EVP_PKEY_METHOD ec_pkey_meth, hmac_pkey_meth;
 
 static const EVP_PKEY_METHOD *standard_methods[] =
        {
        &rsa_pkey_meth,
        &dh_pkey_meth,
        &dsa_pkey_meth,
-       &ec_pkey_meth
+       &ec_pkey_meth,
+       &hmac_pkey_meth,
        };
 
 static int pmeth_cmp(const EVP_PKEY_METHOD * const *a,
index 01f10c3..5f7df5d 100644 (file)
@@ -17,8 +17,8 @@ TEST=hmactest.c
 APPS=
 
 LIB=$(TOP)/libcrypto.a
-LIBSRC=hmac.c
-LIBOBJ=hmac.o
+LIBSRC=hmac.c hm_ameth.c hm_pmeth.c
+LIBOBJ=hmac.o hm_ameth.o hm_pmeth.o
 
 SRC= $(LIBSRC)
 
diff --git a/crypto/hmac/hm_ameth.c b/crypto/hmac/hm_ameth.c
new file mode 100644 (file)
index 0000000..204bdb2
--- /dev/null
@@ -0,0 +1,154 @@
+/* Written by Dr Stephen N Henson (shenson@bigfoot.com) for the OpenSSL
+ * project 2007.
+ */
+/* ====================================================================
+ * Copyright (c) 2007 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
+ *    licensing@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.
+ * ====================================================================
+ *
+ * This product includes cryptographic software written by Eric Young
+ * (eay@cryptsoft.com).  This product includes software written by Tim
+ * Hudson (tjh@cryptsoft.com).
+ *
+ */
+
+#include <stdio.h>
+#include "cryptlib.h"
+#include <openssl/evp.h>
+#include "asn1_locl.h"
+
+#define HMAC_TEST_PRIVATE_KEY_FORMAT
+
+/* HMAC "ASN1" method. This is just here to indicate the
+ * maximum HMAC output length and to free up an HMAC
+ * key.
+ */
+
+static int hmac_size(const EVP_PKEY *pkey)
+       {
+       return EVP_MAX_MD_SIZE;
+       }
+
+static void hmac_key_free(EVP_PKEY *pkey)
+       {
+       ASN1_OCTET_STRING *os = (ASN1_OCTET_STRING *)pkey->pkey.ptr;
+       if (os)
+               {
+               if (os->data)
+                       OPENSSL_cleanse(os->data, os->length);
+               ASN1_OCTET_STRING_free(os);
+               }
+       }
+
+
+#ifdef HMAC_TEST_PRIVATE_KEY_FORMAT
+/* A bogus private key format for test purposes. This is simply the
+ * HMAC key with "HMAC PRIVATE KEY" in the headers. When enabled the
+ * genpkey utility can be used to "generate" HMAC keys.
+ */
+
+static int old_hmac_decode(EVP_PKEY *pkey,
+                                       const unsigned char **pder, int derlen)
+       {
+       ASN1_OCTET_STRING *os;
+       os = ASN1_OCTET_STRING_new();
+       if (!os || !ASN1_OCTET_STRING_set(os, *pder, derlen))
+               return 0;
+       EVP_PKEY_assign(pkey, EVP_PKEY_HMAC, os);
+       return 1;
+       }
+
+static int old_hmac_encode(const EVP_PKEY *pkey, unsigned char **pder)
+       {
+       int inc;
+       ASN1_OCTET_STRING *os = (ASN1_OCTET_STRING *)pkey->pkey.ptr;
+       if (pder)
+               {
+               if (!*pder)
+                       {
+                       *pder = OPENSSL_malloc(os->length);
+                       inc = 0;
+                       }
+               else inc = 1;
+
+               memcpy(*pder, os->data, os->length);
+
+               if (inc)
+                       *pder += os->length;
+               }
+                       
+       return os->length;
+       }
+
+#endif
+
+const EVP_PKEY_ASN1_METHOD hmac_asn1_meth = 
+       {
+       EVP_PKEY_HMAC,
+       EVP_PKEY_HMAC,
+       0,
+
+       "HMAC",
+       "OpenSSL HMAC method",
+
+       0,0,0,0,
+
+       0,0,0,
+
+       hmac_size,
+       0,
+       0,0,0,0,0,0,
+
+       hmac_key_free,
+       0,
+#ifdef HMAC_TEST_PRIVATE_KEY_FORMAT
+       old_hmac_decode,
+       old_hmac_encode
+#else
+       0,0
+#endif
+       };
+
diff --git a/crypto/hmac/hm_pmeth.c b/crypto/hmac/hm_pmeth.c
new file mode 100644 (file)
index 0000000..3e5f4a1
--- /dev/null
@@ -0,0 +1,260 @@
+/* Written by Dr Stephen N Henson (shenson@bigfoot.com) for the OpenSSL
+ * project 2007.
+ */
+/* ====================================================================
+ * Copyright (c) 2007 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
+ *    licensing@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.
+ * ====================================================================
+ *
+ * This product includes cryptographic software written by Eric Young
+ * (eay@cryptsoft.com).  This product includes software written by Tim
+ * Hudson (tjh@cryptsoft.com).
+ *
+ */
+
+#include <stdio.h>
+#include "cryptlib.h"
+#include <openssl/x509.h>
+#include <openssl/x509v3.h>
+#include <openssl/evp.h>
+#include <openssl/hmac.h>
+#include "evp_locl.h"
+
+/* HMAC pkey context structure */
+
+typedef struct
+       {
+       const EVP_MD *md;       /* MD for HMAC use */
+       EVP_MD_CTX *mctx;       /* Parent EVP_MD_CTX */
+       ASN1_OCTET_STRING ktmp; /* Temp storage for key */
+       HMAC_CTX ctx;
+       } HMAC_PKEY_CTX;
+
+static int pkey_hmac_init(EVP_PKEY_CTX *ctx)
+       {
+       HMAC_PKEY_CTX *hctx;
+       hctx = OPENSSL_malloc(sizeof(HMAC_PKEY_CTX));
+       if (!hctx)
+               return 0;
+       hctx->md = NULL;
+       hctx->mctx = NULL;
+       hctx->ktmp.data = NULL;
+       HMAC_CTX_init(&hctx->ctx);
+
+       ctx->data = hctx;
+       ctx->keygen_info_count = 0;
+       
+       return 1;
+       }
+
+static int pkey_hmac_copy(EVP_PKEY_CTX *dst, EVP_PKEY_CTX *src)
+       {
+       HMAC_PKEY_CTX *sctx, *dctx;
+       if (!pkey_hmac_init(dst))
+               return 0;
+               sctx = src->data;
+       dctx = dst->data;
+       dctx->md = sctx->md;
+       HMAC_CTX_init(&dctx->ctx);
+       HMAC_CTX_copy(&dctx->ctx, &sctx->ctx);
+       if (sctx->ktmp.data)
+               {
+               if (!ASN1_OCTET_STRING_set(&dctx->ktmp,
+                                       sctx->ktmp.data, sctx->ktmp.length))
+                       return 0;
+               }
+       return 1;
+       }
+
+static void pkey_hmac_cleanup(EVP_PKEY_CTX *ctx)
+       {
+       HMAC_PKEY_CTX *hctx = ctx->data;
+       HMAC_CTX_cleanup(&hctx->ctx);
+       if (hctx->ktmp.data)
+               {
+               OPENSSL_cleanse(hctx->ktmp.data, hctx->ktmp.length);
+               OPENSSL_free(hctx->ktmp.data);
+               hctx->ktmp.data = NULL;
+               }
+       OPENSSL_free(hctx);
+       }
+
+static int pkey_hmac_keygen(EVP_PKEY_CTX *ctx, EVP_PKEY *pkey)
+       {
+       ASN1_OCTET_STRING *hkey = NULL;
+       HMAC_PKEY_CTX *hctx = ctx->data;
+       if (!hctx->ktmp.data)
+               return 0;
+       hkey = ASN1_OCTET_STRING_dup(&hctx->ktmp);
+       if (!hkey)
+               return 0;
+       EVP_PKEY_assign(pkey, EVP_PKEY_HMAC, hkey);
+       
+       return 1;
+       }
+
+static int int_update(EVP_MD_CTX *ctx,const void *data,size_t count)
+       {
+       HMAC_PKEY_CTX *hctx = ctx->pctx->data;
+       HMAC_Update(&hctx->ctx, data, count);
+       return 1;
+       }
+
+static int hmac_signctx_init(EVP_PKEY_CTX *ctx, EVP_MD_CTX *mctx)
+       {
+       HMAC_PKEY_CTX *hctx = ctx->data;
+       hctx->mctx = mctx;
+       EVP_MD_CTX_set_flags(mctx, EVP_MD_CTX_FLAG_NO_INIT);
+       mctx->update = int_update;
+       return 1;
+       }
+
+static int hmac_signctx(EVP_PKEY_CTX *ctx, unsigned char *sig, size_t *siglen,
+                                       EVP_MD_CTX *mctx)
+       {
+       unsigned int hlen;
+       HMAC_PKEY_CTX *hctx = ctx->data;
+       *siglen = EVP_MD_CTX_size(mctx);
+       if (!sig)
+               return 1;
+
+       HMAC_Final(&hctx->ctx, sig, &hlen);
+       *siglen = (size_t)hlen;
+       return 1;
+       }
+
+static int pkey_hmac_ctrl(EVP_PKEY_CTX *ctx, int type, int p1, void *p2)
+       {
+       HMAC_PKEY_CTX *hctx = ctx->data;
+       ASN1_OCTET_STRING *key;
+       switch (type)
+               {
+
+               case EVP_PKEY_CTRL_SET_MAC_KEY:
+               if ((!p2 && p1 > 0) || (p1 < -1))
+                       return 0;
+               if (!ASN1_OCTET_STRING_set(&hctx->ktmp, p2, p1))
+                       return 0;
+               break;
+
+               case EVP_PKEY_CTRL_MD:
+               hctx->md = p2;
+               break;
+
+               case EVP_PKEY_CTRL_DIGESTINIT:
+               key = (ASN1_OCTET_STRING *)ctx->pkey->pkey.ptr;
+               HMAC_Init_ex(&hctx->ctx, key->data, key->length, hctx->md,
+                               ctx->engine);
+               break;
+
+               default:
+               return -2;
+
+               }
+       return 1;
+       }
+
+static int pkey_hmac_ctrl_str(EVP_PKEY_CTX *ctx,
+                       const char *type, const char *value)
+       {
+       if (!value)
+               {
+               return 0;
+               }
+       if (!strcmp(type, "key"))
+               {
+               return pkey_hmac_ctrl(ctx, EVP_PKEY_CTRL_SET_MAC_KEY,
+                               -1, (void *)value);
+               }
+       if (!strcmp(type, "hexkey"))
+               {
+               unsigned char *key;
+               int r;
+               long keylen;
+               key = string_to_hex(value, &keylen);
+               if (!key)
+                       return 0;
+               r = pkey_hmac_ctrl(ctx, EVP_PKEY_CTRL_SET_MAC_KEY, keylen, key);
+               OPENSSL_free(key);
+               return r;
+               }
+       return -2;
+       }
+
+const EVP_PKEY_METHOD hmac_pkey_meth = 
+       {
+       EVP_PKEY_HMAC,
+       0,
+       pkey_hmac_init,
+       pkey_hmac_copy,
+       pkey_hmac_cleanup,
+
+       0, 0,
+
+       0,
+       pkey_hmac_keygen,
+
+       0, 0,
+
+       0, 0,
+
+       0,0,
+
+       hmac_signctx_init,
+       hmac_signctx,
+
+       0,0,
+
+       0,0,
+
+       0,0,
+
+       0,0,
+
+       pkey_hmac_ctrl,
+       pkey_hmac_ctrl_str
+
+       };
index c45e001..5c99f03 100644 (file)
@@ -147,6 +147,16 @@ void HMAC_CTX_init(HMAC_CTX *ctx)
        EVP_MD_CTX_init(&ctx->md_ctx);
        }
 
+void HMAC_CTX_copy(HMAC_CTX *dctx, HMAC_CTX *sctx)
+       {
+       EVP_MD_CTX_copy(&dctx->i_ctx, &sctx->i_ctx);
+       EVP_MD_CTX_copy(&dctx->o_ctx, &sctx->o_ctx);
+       EVP_MD_CTX_copy(&dctx->md_ctx, &sctx->md_ctx);
+       memcpy(dctx->key, sctx->key, HMAC_MAX_MD_CBLOCK);
+       dctx->key_length = sctx->key_length;
+       dctx->md = sctx->md;
+       }
+
 void HMAC_CTX_cleanup(HMAC_CTX *ctx)
        {
        EVP_MD_CTX_cleanup(&ctx->i_ctx);
index 719fc40..bdacf4d 100644 (file)
@@ -99,6 +99,7 @@ void HMAC_Final(HMAC_CTX *ctx, unsigned char *md, unsigned int *len);
 unsigned char *HMAC(const EVP_MD *evp_md, const void *key, int key_len,
                    const unsigned char *d, size_t n, unsigned char *md,
                    unsigned int *md_len);
+void HMAC_CTX_copy(HMAC_CTX *dctx, HMAC_CTX *sctx);
 
 
 #ifdef  __cplusplus
index 8dad99c..5108a3b 100644 (file)
@@ -62,9 +62,9 @@
  * [including the GNU Public Licence.]
  */
 
-#define NUM_NID 836
-#define NUM_SN 832
-#define NUM_LN 832
+#define NUM_NID 837
+#define NUM_SN 833
+#define NUM_LN 833
 #define NUM_OBJ 787
 
 static unsigned char lvalues[5560]={
@@ -2209,6 +2209,7 @@ static ASN1_OBJECT nid_objs[NUM_NID]={
 {"dsa_with_SHA256","dsa_with_SHA256",NID_dsa_with_SHA256,9,
        &(lvalues[5550]),0},
 {"gost89-cnt","gost89-cnt",NID_gost89_cnt,0,NULL,0},
+{"HMAC","hmac",NID_hmac,0,NULL,0},
 };
 
 static ASN1_OBJECT *sn_objs[NUM_SN]={
@@ -2289,6 +2290,7 @@ static ASN1_OBJECT *sn_objs[NUM_SN]={
 &(nid_objs[67]),/* "DSA-old" */
 &(nid_objs[297]),/* "DVCS" */
 &(nid_objs[99]),/* "GN" */
+&(nid_objs[836]),/* "HMAC" */
 &(nid_objs[381]),/* "IANA" */
 &(nid_objs[34]),/* "IDEA-CBC" */
 &(nid_objs[35]),/* "IDEA-CFB" */
@@ -3336,6 +3338,7 @@ static ASN1_OBJECT *ln_objs[NUM_LN]={
 &(nid_objs[601]),/* "generic cryptogram" */
 &(nid_objs[99]),/* "givenName" */
 &(nid_objs[835]),/* "gost89-cnt" */
+&(nid_objs[836]),/* "hmac" */
 &(nid_objs[772]),/* "hmacWithMD5" */
 &(nid_objs[163]),/* "hmacWithSHA1" */
 &(nid_objs[773]),/* "hmacWithSHA224" */
index 131199a..6461c34 100644 (file)
 #define LN_camellia_256_cfb8           "camellia-256-cfb8"
 #define NID_camellia_256_cfb8          765
 
+#define SN_hmac                "HMAC"
+#define LN_hmac                "hmac"
+#define NID_hmac               836
+
index b9d34d2..3ca42fe 100644 (file)
@@ -833,3 +833,4 @@ ecdsa_with_SHA512           832
 dsa_with_SHA224                833
 dsa_with_SHA256                834
 gost89_cnt             835
+hmac           836
index 1f48abf..8bd9653 100644 (file)
@@ -1188,3 +1188,7 @@ camellia 44               : CAMELLIA-256-CFB              : camellia-256-cfb
                        : CAMELLIA-128-CFB8             : camellia-128-cfb8
                        : CAMELLIA-192-CFB8             : camellia-192-cfb8
                        : CAMELLIA-256-CFB8             : camellia-256-cfb8
+
+# There is no OID that just denotes "HMAC" oddly enough...
+
+                       : HMAC                          : hmac