summaryrefslogtreecommitdiffstats
path: root/crypto/asn1
diff options
context:
space:
mode:
authorDr. Stephen Henson <steve@openssl.org>2011-10-09 23:13:50 +0000
committerDr. Stephen Henson <steve@openssl.org>2011-10-09 23:13:50 +0000
commit9309ea66177f927aefa14bf317a578427139a0fc (patch)
treedde4b5ce742168c5860279a634457045ac562e17 /crypto/asn1
parent05c9e3aea584c4d618dc32a4825287f06828a537 (diff)
Backport PSS signature support from HEAD.
Diffstat (limited to 'crypto/asn1')
-rw-r--r--crypto/asn1/a_sign.c105
-rw-r--r--crypto/asn1/a_verify.c63
-rw-r--r--crypto/asn1/asn1.h7
-rw-r--r--crypto/asn1/asn1_err.c2
-rw-r--r--crypto/asn1/asn1_locl.h11
-rw-r--r--crypto/asn1/t_crl.c3
-rw-r--r--crypto/asn1/t_x509.c42
7 files changed, 167 insertions, 66 deletions
diff --git a/crypto/asn1/a_sign.c b/crypto/asn1/a_sign.c
index d96a622d83..7b4a193d6b 100644
--- a/crypto/asn1/a_sign.c
+++ b/crypto/asn1/a_sign.c
@@ -218,65 +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(it, algor1, algor2, signature, asn, &ctx);
+ }
+
+
+int ASN1_item_sign_ctx(const ASN1_ITEM *it,
+ X509_ALGOR *algor1, X509_ALGOR *algor2,
+ ASN1_BIT_STRING *signature, void *asn, EVP_MD_CTX *ctx)
+ {
+ const EVP_MD *type;
+ EVP_PKEY *pkey;
unsigned char *buf_in=NULL,*buf_out=NULL;
- int inl=0,outl=0,outll=0;
+ size_t inl=0,outl=0,outll=0;
int signid, paramtype;
+ int rv;
- if (type == NULL)
+ type = EVP_MD_CTX_md(ctx);
+ pkey = EVP_PKEY_CTX_get0_pkey(ctx->pctx);
+
+ 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_SignInit_ex(&ctx,type, NULL)
- || !EVP_SignUpdate(&ctx,(unsigned char *)buf_in,inl)
- || !EVP_SignFinal(&ctx,(unsigned char *)buf_out,
- (unsigned int *)&outl,pkey))
+ 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);
@@ -289,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)
diff --git a/crypto/asn1/a_verify.c b/crypto/asn1/a_verify.c
index d9332ee15d..432722e409 100644
--- a/crypto/asn1/a_verify.c
+++ b/crypto/asn1/a_verify.c
@@ -131,11 +131,10 @@ err:
#endif
-int ASN1_item_verify(const ASN1_ITEM *it, X509_ALGOR *a, ASN1_BIT_STRING *signature,
- void *asn, EVP_PKEY *pkey)
+int ASN1_item_verify(const ASN1_ITEM *it, X509_ALGOR *a,
+ ASN1_BIT_STRING *signature, void *asn, EVP_PKEY *pkey)
{
EVP_MD_CTX ctx;
- const EVP_MD *type = NULL;
unsigned char *buf_in=NULL;
int ret= -1,inl;
@@ -149,25 +148,47 @@ int ASN1_item_verify(const ASN1_ITEM *it, X509_ALGOR *a, ASN1_BIT_STRING *signat
ASN1err(ASN1_F_ASN1_ITEM_VERIFY,ASN1_R_UNKNOWN_SIGNATURE_ALGORITHM);
goto err;
}
- type=EVP_get_digestbynid(mdnid);
- if (type == NULL)
+ if (mdnid == NID_undef)
{
- ASN1err(ASN1_F_ASN1_ITEM_VERIFY,ASN1_R_UNKNOWN_MESSAGE_DIGEST_ALGORITHM);
- goto err;
+ if (!pkey->ameth || !pkey->ameth->item_verify)
+ {
+ ASN1err(ASN1_F_ASN1_ITEM_VERIFY,ASN1_R_UNKNOWN_SIGNATURE_ALGORITHM);
+ goto err;
+ }
+ ret = pkey->ameth->item_verify(&ctx, it, asn, a,
+ signature, pkey);
+ /* Return value of 2 means carry on, anything else means we
+ * exit straight away: either a fatal error of the underlying
+ * verification routine handles all verification.
+ */
+ if (ret != 2)
+ goto err;
+ ret = -1;
}
-
- /* Check public key OID matches public key type */
- if (EVP_PKEY_type(pknid) != pkey->ameth->pkey_id)
+ else
{
- ASN1err(ASN1_F_ASN1_ITEM_VERIFY,ASN1_R_WRONG_PUBLIC_KEY_TYPE);
- goto err;
- }
+ const EVP_MD *type;
+ type=EVP_get_digestbynid(mdnid);
+ if (type == NULL)
+ {
+ ASN1err(ASN1_F_ASN1_ITEM_VERIFY,ASN1_R_UNKNOWN_MESSAGE_DIGEST_ALGORITHM);
+ goto err;
+ }
+
+ /* Check public key OID matches public key type */
+ if (EVP_PKEY_type(pknid) != pkey->ameth->pkey_id)
+ {
+ ASN1err(ASN1_F_ASN1_ITEM_VERIFY,ASN1_R_WRONG_PUBLIC_KEY_TYPE);
+ goto err;
+ }
+
+ if (!EVP_DigestVerifyInit(&ctx, NULL, type, NULL, pkey))
+ {
+ ASN1err(ASN1_F_ASN1_ITEM_VERIFY,ERR_R_EVP_LIB);
+ ret=0;
+ goto err;
+ }
- if (!EVP_VerifyInit_ex(&ctx,type, NULL))
- {
- ASN1err(ASN1_F_ASN1_ITEM_VERIFY,ERR_R_EVP_LIB);
- ret=0;
- goto err;
}
inl = ASN1_item_i2d(asn, &buf_in, it);
@@ -178,7 +199,7 @@ int ASN1_item_verify(const ASN1_ITEM *it, X509_ALGOR *a, ASN1_BIT_STRING *signat
goto err;
}
- if (!EVP_VerifyUpdate(&ctx,(unsigned char *)buf_in,inl))
+ if (!EVP_DigestVerifyUpdate(&ctx,buf_in,inl))
{
ASN1err(ASN1_F_ASN1_ITEM_VERIFY,ERR_R_EVP_LIB);
ret=0;
@@ -188,8 +209,8 @@ int ASN1_item_verify(const ASN1_ITEM *it, X509_ALGOR *a, ASN1_BIT_STRING *signat
OPENSSL_cleanse(buf_in,(unsigned int)inl);
OPENSSL_free(buf_in);
- if (EVP_VerifyFinal(&ctx,(unsigned char *)signature->data,
- (unsigned int)signature->length,pkey) <= 0)
+ if (EVP_DigestVerifyFinal(&ctx,signature->data,
+ (size_t)signature->length) <= 0)
{
ASN1err(ASN1_F_ASN1_ITEM_VERIFY,ERR_R_EVP_LIB);
ret=0;
diff --git a/crypto/asn1/asn1.h b/crypto/asn1/asn1.h
index 439e76044a..220a0c8c63 100644
--- a/crypto/asn1/asn1.h
+++ b/crypto/asn1/asn1.h
@@ -235,7 +235,7 @@ typedef struct asn1_object_st
*/
#define ASN1_STRING_FLAG_MSTRING 0x040
/* This is the base type that holds just about everything :-) */
-typedef struct asn1_string_st
+struct asn1_string_st
{
int length;
int type;
@@ -245,7 +245,7 @@ typedef struct asn1_string_st
* input data has a non-zero 'unused bits' value, it will be
* handled correctly */
long flags;
- } ASN1_STRING;
+ };
/* ASN1_ENCODING structure: this is used to save the received
* encoding of an ASN1 type. This is useful to get round
@@ -293,7 +293,6 @@ DECLARE_STACK_OF(ASN1_STRING_TABLE)
* see asn1t.h
*/
typedef struct ASN1_TEMPLATE_st ASN1_TEMPLATE;
-typedef struct ASN1_ITEM_st ASN1_ITEM;
typedef struct ASN1_TLC_st ASN1_TLC;
/* This is just an opaque pointer */
typedef struct ASN1_VALUE_st ASN1_VALUE;
@@ -1194,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
@@ -1292,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
diff --git a/crypto/asn1/asn1_err.c b/crypto/asn1/asn1_err.c
index 7e209956e6..1a30bf119b 100644
--- a/crypto/asn1/asn1_err.c
+++ b/crypto/asn1/asn1_err.c
@@ -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"},
diff --git a/crypto/asn1/asn1_locl.h b/crypto/asn1/asn1_locl.h
index 5aa65e28f5..9fcf0d9530 100644
--- a/crypto/asn1/asn1_locl.h
+++ b/crypto/asn1/asn1_locl.h
@@ -102,6 +102,10 @@ struct evp_pkey_asn1_method_st
int (*param_cmp)(const EVP_PKEY *a, const EVP_PKEY *b);
int (*param_print)(BIO *out, const EVP_PKEY *pkey, int indent,
ASN1_PCTX *pctx);
+ int (*sig_print)(BIO *out,
+ const X509_ALGOR *sigalg, const ASN1_STRING *sig,
+ int indent, ASN1_PCTX *pctx);
+
void (*pkey_free)(EVP_PKEY *pkey);
int (*pkey_ctrl)(EVP_PKEY *pkey, int op, long arg1, void *arg2);
@@ -111,6 +115,13 @@ struct evp_pkey_asn1_method_st
int (*old_priv_decode)(EVP_PKEY *pkey,
const unsigned char **pder, int derlen);
int (*old_priv_encode)(const EVP_PKEY *pkey, unsigned char **pder);
+ /* Custom ASN1 signature verification */
+ 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 */;
diff --git a/crypto/asn1/t_crl.c b/crypto/asn1/t_crl.c
index ee5a687ce8..c61169208a 100644
--- a/crypto/asn1/t_crl.c
+++ b/crypto/asn1/t_crl.c
@@ -94,8 +94,7 @@ int X509_CRL_print(BIO *out, X509_CRL *x)
l = X509_CRL_get_version(x);
BIO_printf(out, "%8sVersion %lu (0x%lx)\n", "", l+1, l);
i = OBJ_obj2nid(x->sig_alg->algorithm);
- BIO_printf(out, "%8sSignature Algorithm: %s\n", "",
- (i == NID_undef) ? "NONE" : OBJ_nid2ln(i));
+ X509_signature_print(out, x->sig_alg, NULL);
p=X509_NAME_oneline(X509_CRL_get_issuer(x),NULL,0);
BIO_printf(out,"%8sIssuer: %s\n","",p);
OPENSSL_free(p);
diff --git a/crypto/asn1/t_x509.c b/crypto/asn1/t_x509.c
index 01cf9e427a..db88f3a3e1 100644
--- a/crypto/asn1/t_x509.c
+++ b/crypto/asn1/t_x509.c
@@ -72,6 +72,7 @@
#include <openssl/objects.h>
#include <openssl/x509.h>
#include <openssl/x509v3.h>
+#include "asn1_locl.h"
#ifndef OPENSSL_NO_FP_API
int X509_print_fp(FILE *fp, X509 *x)
@@ -167,12 +168,16 @@ int X509_print_ex(BIO *bp, X509 *x, unsigned long nmflags, unsigned long cflag)
if(!(cflag & X509_FLAG_NO_SIGNAME))
{
+ if(X509_signature_print(bp, x->sig_alg, NULL) <= 0)
+ goto err;
+#if 0
if (BIO_printf(bp,"%8sSignature Algorithm: ","") <= 0)
goto err;
if (i2a_ASN1_OBJECT(bp, ci->signature->algorithm) <= 0)
goto err;
if (BIO_puts(bp, "\n") <= 0)
goto err;
+#endif
}
if(!(cflag & X509_FLAG_NO_ISSUER))
@@ -286,23 +291,50 @@ err:
return(0);
}
-int X509_signature_print(BIO *bp, X509_ALGOR *sigalg, ASN1_STRING *sig)
+int X509_signature_dump(BIO *bp, const ASN1_STRING *sig, int indent)
{
- unsigned char *s;
+ const unsigned char *s;
int i, n;
- if (BIO_puts(bp," Signature Algorithm: ") <= 0) return 0;
- if (i2a_ASN1_OBJECT(bp, sigalg->algorithm) <= 0) return 0;
n=sig->length;
s=sig->data;
for (i=0; i<n; i++)
{
if ((i%18) == 0)
- if (BIO_write(bp,"\n ",9) <= 0) return 0;
+ {
+ if (BIO_write(bp,"\n",1) <= 0) return 0;
+ if (BIO_indent(bp, indent, indent) <= 0) return 0;
+ }
if (BIO_printf(bp,"%02x%s",s[i],
((i+1) == n)?"":":") <= 0) return 0;
}
if (BIO_write(bp,"\n",1) != 1) return 0;
+
+ return 1;
+}
+
+int X509_signature_print(BIO *bp, X509_ALGOR *sigalg, ASN1_STRING *sig)
+{
+ int sig_nid;
+ if (BIO_puts(bp," Signature Algorithm: ") <= 0) return 0;
+ if (i2a_ASN1_OBJECT(bp, sigalg->algorithm) <= 0) return 0;
+
+ sig_nid = OBJ_obj2nid(sigalg->algorithm);
+ if (sig_nid != NID_undef)
+ {
+ int pkey_nid, dig_nid;
+ const EVP_PKEY_ASN1_METHOD *ameth;
+ if (OBJ_find_sigid_algs(sig_nid, &dig_nid, &pkey_nid))
+ {
+ ameth = EVP_PKEY_asn1_find(NULL, pkey_nid);
+ if (ameth && ameth->sig_print)
+ return ameth->sig_print(bp, sigalg, sig, 9, 0);
+ }
+ }
+ if (sig)
+ return X509_signature_dump(bp, sig, 9);
+ else if (BIO_puts(bp, "\n") <= 0)
+ return 0;
return 1;
}