Algorithm specific ASN1 signing functions.
authorDr. Stephen Henson <steve@openssl.org>
Thu, 11 Mar 2010 13:32:38 +0000 (13:32 +0000)
committerDr. Stephen Henson <steve@openssl.org>
Thu, 11 Mar 2010 13:32:38 +0000 (13:32 +0000)
CHANGES
crypto/asn1/a_sign.c
crypto/asn1/asn1.h
crypto/asn1/asn1_err.c
crypto/asn1/asn1_locl.h

diff --git a/CHANGES b/CHANGES
index 674a2f1..fad16c1 100644 (file)
--- a/CHANGES
+++ b/CHANGES
@@ -4,6 +4,12 @@
 
  Changes between 1.0.0 and 1.1.0  [xx XXX xxxx]
 
+  *) Support for companion algorithm specific ASN1 signing routines.
+     New function ASN1_item_sign_ctx() signs a pre-initialised
+     EVP_MD_CTX structure and sets AlgorithmIdentifiers based on
+     the appropriate parameters.
+     [Steve Henson]
+
   *) Add new algorithm specific ASN1 verification initialisation function
      to EVP_PKEY_ASN1_METHOD: this is not in EVP_PKEY_METHOD since the ASN1
      handling will be the same no matter what EVP_PKEY_METHOD is used.
index 27deb89..f1ec73a 100644 (file)
@@ -218,64 +218,100 @@ int ASN1_item_sign(const ASN1_ITEM *it, X509_ALGOR *algor1, X509_ALGOR *algor2,
             const EVP_MD *type)
        {
        EVP_MD_CTX ctx;
+       EVP_MD_CTX_init(&ctx);
+       if (!EVP_DigestSignInit(&ctx, NULL, type, NULL, pkey))
+               {
+               EVP_MD_CTX_cleanup(&ctx);
+               return 0;
+               }
+       return ASN1_item_sign_ctx(&ctx, it, algor1, algor2, signature, asn);
+       }
+               
+
+int ASN1_item_sign_ctx(EVP_MD_CTX *ctx,
+               const ASN1_ITEM *it, X509_ALGOR *algor1, X509_ALGOR *algor2,
+               ASN1_BIT_STRING *signature, void *asn)
+       {
+       const EVP_MD *type;
+       EVP_PKEY *pkey;
        unsigned char *buf_in=NULL,*buf_out=NULL;
        size_t inl=0,outl=0,outll=0;
        int signid, paramtype;
+       int rv;
+
+       type = EVP_MD_CTX_md(ctx);
+       pkey = EVP_PKEY_CTX_get0_pkey(ctx->pctx);
 
-       if (type == NULL)
+       if (!type || !pkey)
                {
-               int def_nid;
-               if (EVP_PKEY_get_default_digest_nid(pkey, &def_nid) > 0)
-                       type = EVP_get_digestbynid(def_nid);
+               ASN1err(ASN1_F_ASN1_ITEM_SIGN_CTX, ASN1_R_CONTEXT_NOT_INITIALISED);
+               return 0;
                }
 
-       if (type == NULL)
+       if (pkey->ameth->item_sign)
                {
-               ASN1err(ASN1_F_ASN1_ITEM_SIGN, ASN1_R_NO_DEFAULT_DIGEST);
-               return 0;
+               rv = pkey->ameth->item_sign(ctx, it, asn, algor1, algor2,
+                                               signature);
+               if (rv == 1)
+                       outl = signature->length;
+               /* Return value meanings:
+                * <=0: error.
+                *   1: method does everything.
+                *   2: carry on as normal.
+                *   3: ASN1 method sets algorithm identifiers: just sign.
+                */
+               if (rv <= 0)
+                       ASN1err(ASN1_F_ASN1_ITEM_SIGN_CTX, ERR_R_EVP_LIB);
+               if (rv <= 1)
+                       goto err;
                }
+       else
+               rv = 2;
 
-       if (type->flags & EVP_MD_FLAG_PKEY_METHOD_SIGNATURE)
+       if (rv == 2)
                {
-               if (!pkey->ameth ||
-                       !OBJ_find_sigid_by_algs(&signid, EVP_MD_nid(type),
-                                               pkey->ameth->pkey_id))
+               if (type->flags & EVP_MD_FLAG_PKEY_METHOD_SIGNATURE)
                        {
-                       ASN1err(ASN1_F_ASN1_ITEM_SIGN,
-                               ASN1_R_DIGEST_AND_KEY_TYPE_NOT_SUPPORTED);
-                       return 0;
+                       if (!pkey->ameth ||
+                               !OBJ_find_sigid_by_algs(&signid,
+                                                       EVP_MD_nid(type),
+                                                       pkey->ameth->pkey_id))
+                               {
+                               ASN1err(ASN1_F_ASN1_ITEM_SIGN_CTX,
+                                       ASN1_R_DIGEST_AND_KEY_TYPE_NOT_SUPPORTED);
+                               return 0;
+                               }
                        }
-               }
-       else
-               signid = type->pkey_type;
+               else
+                       signid = type->pkey_type;
 
-       if (pkey->ameth->pkey_flags & ASN1_PKEY_SIGPARAM_NULL)
-               paramtype = V_ASN1_NULL;
-       else
-               paramtype = V_ASN1_UNDEF;
+               if (pkey->ameth->pkey_flags & ASN1_PKEY_SIGPARAM_NULL)
+                       paramtype = V_ASN1_NULL;
+               else
+                       paramtype = V_ASN1_UNDEF;
 
-       if (algor1)
-               X509_ALGOR_set0(algor1, OBJ_nid2obj(signid), paramtype, NULL);
-       if (algor2)
-               X509_ALGOR_set0(algor2, OBJ_nid2obj(signid), paramtype, NULL);
+               if (algor1)
+                       X509_ALGOR_set0(algor1, OBJ_nid2obj(signid), paramtype, NULL);
+               if (algor2)
+                       X509_ALGOR_set0(algor2, OBJ_nid2obj(signid), paramtype, NULL);
+
+               }
 
-       EVP_MD_CTX_init(&ctx);
        inl=ASN1_item_i2d(asn,&buf_in, it);
        outll=outl=EVP_PKEY_size(pkey);
-       buf_out=(unsigned char *)OPENSSL_malloc((unsigned int)outl);
+       buf_out=OPENSSL_malloc((unsigned int)outl);
        if ((buf_in == NULL) || (buf_out == NULL))
                {
                outl=0;
-               ASN1err(ASN1_F_ASN1_ITEM_SIGN,ERR_R_MALLOC_FAILURE);
+               ASN1err(ASN1_F_ASN1_ITEM_SIGN_CTX,ERR_R_MALLOC_FAILURE);
                goto err;
                }
 
-       if (!EVP_DigestSignInit(&ctx, NULL, type, NULL, pkey)
-               || !EVP_DigestSignUpdate(&ctx, buf_in, inl)
-               || !EVP_DigestSignFinal(&ctx, buf_out, &outl))
+       if (!EVP_DigestSignUpdate(ctx, buf_in, inl)
+               || !EVP_DigestSignFinal(ctx, buf_out, &outl))
                {
                outl=0;
-               ASN1err(ASN1_F_ASN1_ITEM_SIGN,ERR_R_EVP_LIB);
+               ASN1err(ASN1_F_ASN1_ITEM_SIGN_CTX,ERR_R_EVP_LIB);
                goto err;
                }
        if (signature->data != NULL) OPENSSL_free(signature->data);
@@ -288,7 +324,7 @@ int ASN1_item_sign(const ASN1_ITEM *it, X509_ALGOR *algor1, X509_ALGOR *algor2,
        signature->flags&= ~(ASN1_STRING_FLAG_BITS_LEFT|0x07);
        signature->flags|=ASN1_STRING_FLAG_BITS_LEFT;
 err:
-       EVP_MD_CTX_cleanup(&ctx);
+       EVP_MD_CTX_cleanup(ctx);
        if (buf_in != NULL)
                { OPENSSL_cleanse((char *)buf_in,(unsigned int)inl); OPENSSL_free(buf_in); }
        if (buf_out != NULL)
index a074318..45e8fe3 100644 (file)
@@ -1193,6 +1193,7 @@ void ERR_load_ASN1_strings(void);
 #define ASN1_F_ASN1_ITEM_I2D_FP                                 193
 #define ASN1_F_ASN1_ITEM_PACK                           198
 #define ASN1_F_ASN1_ITEM_SIGN                           195
+#define ASN1_F_ASN1_ITEM_SIGN_CTX                       220
 #define ASN1_F_ASN1_ITEM_UNPACK                                 199
 #define ASN1_F_ASN1_ITEM_VERIFY                                 197
 #define ASN1_F_ASN1_MBSTRING_NCOPY                      122
@@ -1291,6 +1292,7 @@ void ERR_load_ASN1_strings(void);
 #define ASN1_R_BOOLEAN_IS_WRONG_LENGTH                  106
 #define ASN1_R_BUFFER_TOO_SMALL                                 107
 #define ASN1_R_CIPHER_HAS_NO_OBJECT_IDENTIFIER          108
+#define ASN1_R_CONTEXT_NOT_INITIALISED                  217
 #define ASN1_R_DATA_IS_WRONG                            109
 #define ASN1_R_DECODE_ERROR                             110
 #define ASN1_R_DECODING_ERROR                           111
index 570ec38..7d0dfd8 100644 (file)
@@ -1,6 +1,6 @@
 /* crypto/asn1/asn1_err.c */
 /* ====================================================================
- * Copyright (c) 1999-2009 The OpenSSL Project.  All rights reserved.
+ * Copyright (c) 1999-2010 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
@@ -107,6 +107,7 @@ static ERR_STRING_DATA ASN1_str_functs[]=
 {ERR_FUNC(ASN1_F_ASN1_ITEM_I2D_FP),    "ASN1_item_i2d_fp"},
 {ERR_FUNC(ASN1_F_ASN1_ITEM_PACK),      "ASN1_item_pack"},
 {ERR_FUNC(ASN1_F_ASN1_ITEM_SIGN),      "ASN1_item_sign"},
+{ERR_FUNC(ASN1_F_ASN1_ITEM_SIGN_CTX),  "ASN1_item_sign_ctx"},
 {ERR_FUNC(ASN1_F_ASN1_ITEM_UNPACK),    "ASN1_item_unpack"},
 {ERR_FUNC(ASN1_F_ASN1_ITEM_VERIFY),    "ASN1_item_verify"},
 {ERR_FUNC(ASN1_F_ASN1_MBSTRING_NCOPY), "ASN1_mbstring_ncopy"},
@@ -208,6 +209,7 @@ static ERR_STRING_DATA ASN1_str_reasons[]=
 {ERR_REASON(ASN1_R_BOOLEAN_IS_WRONG_LENGTH),"boolean is wrong length"},
 {ERR_REASON(ASN1_R_BUFFER_TOO_SMALL)     ,"buffer too small"},
 {ERR_REASON(ASN1_R_CIPHER_HAS_NO_OBJECT_IDENTIFIER),"cipher has no object identifier"},
+{ERR_REASON(ASN1_R_CONTEXT_NOT_INITIALISED),"context not initialised"},
 {ERR_REASON(ASN1_R_DATA_IS_WRONG)        ,"data is wrong"},
 {ERR_REASON(ASN1_R_DECODE_ERROR)         ,"decode error"},
 {ERR_REASON(ASN1_R_DECODING_ERROR)       ,"decoding error"},
index ceb3b4e..9fcf0d9 100644 (file)
@@ -119,6 +119,9 @@ struct evp_pkey_asn1_method_st
        int (*item_verify)(EVP_MD_CTX *ctx, const ASN1_ITEM *it, void *asn,
                                X509_ALGOR *a, ASN1_BIT_STRING *sig,
                                EVP_PKEY *pkey);
+       int (*item_sign)(EVP_MD_CTX *ctx, const ASN1_ITEM *it, void *asn,
+                               X509_ALGOR *alg1, X509_ALGOR *alg2, 
+                               ASN1_BIT_STRING *sig);
 
        } /* EVP_PKEY_ASN1_METHOD */;