X-Git-Url: https://git.openssl.org/?a=blobdiff_plain;f=crypto%2Fx509%2Fx509_cmp.c;h=2b5aa09ad9c4a6fc334f786f6fa62a3250f43af4;hb=c99935e32cba193c10e1933ab1b34e3931a52b9a;hp=be2997909204b316b4d25930f68217cd58f4aa0a;hpb=17f389bbbfccf057a8bc04084ed068c4b368e751;p=openssl.git diff --git a/crypto/x509/x509_cmp.c b/crypto/x509/x509_cmp.c index be29979092..2b5aa09ad9 100644 --- a/crypto/x509/x509_cmp.c +++ b/crypto/x509/x509_cmp.c @@ -57,56 +57,60 @@ */ #include +#include #include "cryptlib.h" #include #include #include +#include -int X509_issuer_and_serial_cmp(X509 *a, X509 *b) +int X509_issuer_and_serial_cmp(const X509 *a, const X509 *b) { int i; X509_CINF *ai,*bi; ai=a->cert_info; bi=b->cert_info; - i=ASN1_INTEGER_cmp(ai->serialNumber,bi->serialNumber); + i=M_ASN1_INTEGER_cmp(ai->serialNumber,bi->serialNumber); if (i) return(i); return(X509_NAME_cmp(ai->issuer,bi->issuer)); } -#ifndef NO_MD5 +#ifndef OPENSSL_NO_MD5 unsigned long X509_issuer_and_serial_hash(X509 *a) { unsigned long ret=0; - MD5_CTX ctx; + EVP_MD_CTX ctx; unsigned char md[16]; char str[256]; + EVP_MD_CTX_init(&ctx); X509_NAME_oneline(a->cert_info->issuer,str,256); ret=strlen(str); - MD5_Init(&ctx); - MD5_Update(&ctx,(unsigned char *)str,ret); - MD5_Update(&ctx,(unsigned char *)a->cert_info->serialNumber->data, + EVP_DigestInit_ex(&ctx, EVP_md5(), NULL); + EVP_DigestUpdate(&ctx,(unsigned char *)str,ret); + EVP_DigestUpdate(&ctx,(unsigned char *)a->cert_info->serialNumber->data, (unsigned long)a->cert_info->serialNumber->length); - MD5_Final(&(md[0]),&ctx); + EVP_DigestFinal_ex(&ctx,&(md[0]),NULL); ret=( ((unsigned long)md[0] )|((unsigned long)md[1]<<8L)| ((unsigned long)md[2]<<16L)|((unsigned long)md[3]<<24L) )&0xffffffffL; + EVP_MD_CTX_cleanup(&ctx); return(ret); } #endif -int X509_issuer_name_cmp(X509 *a, X509 *b) +int X509_issuer_name_cmp(const X509 *a, const X509 *b) { return(X509_NAME_cmp(a->cert_info->issuer,b->cert_info->issuer)); } -int X509_subject_name_cmp(X509 *a, X509 *b) +int X509_subject_name_cmp(const X509 *a, const X509 *b) { return(X509_NAME_cmp(a->cert_info->subject,b->cert_info->subject)); } -int X509_CRL_cmp(X509_CRL *a, X509_CRL *b) +int X509_CRL_cmp(const X509_CRL *a, const X509_CRL *b) { return(X509_NAME_cmp(a->crl->issuer,b->crl->issuer)); } @@ -136,7 +140,120 @@ unsigned long X509_subject_name_hash(X509 *x) return(X509_NAME_hash(x->cert_info->subject)); } -int X509_NAME_cmp(X509_NAME *a, X509_NAME *b) +#ifndef OPENSSL_NO_SHA +/* Compare two certificates: they must be identical for + * this to work. NB: Although "cmp" operations are generally + * prototyped to take "const" arguments (eg. for use in + * STACKs), the way X509 handling is - these operations may + * involve ensuring the hashes are up-to-date and ensuring + * certain cert information is cached. So this is the point + * where the "depth-first" constification tree has to halt + * with an evil cast. + */ +int X509_cmp(const X509 *a, const X509 *b) +{ + /* ensure hash is valid */ + X509_check_purpose((X509 *)a, -1, 0); + X509_check_purpose((X509 *)b, -1, 0); + + return memcmp(a->sha1_hash, b->sha1_hash, SHA_DIGEST_LENGTH); +} +#endif + + +/* Case insensitive string comparision */ +static int nocase_cmp(const ASN1_STRING *a, const ASN1_STRING *b) +{ + int i; + + if (a->length != b->length) + return (a->length - b->length); + + for (i=0; ilength; i++) + { + int ca, cb; + + ca = tolower(a->data[i]); + cb = tolower(b->data[i]); + + if (ca != cb) + return(ca-cb); + } + return 0; +} + +/* Case insensitive string comparision with space normalization + * Space normalization - ignore leading, trailing spaces, + * multiple spaces between characters are replaced by single space + */ +static int nocase_spacenorm_cmp(const ASN1_STRING *a, const ASN1_STRING *b) +{ + unsigned char *pa = NULL, *pb = NULL; + int la, lb; + + la = a->length; + lb = b->length; + pa = a->data; + pb = b->data; + + /* skip leading spaces */ + while (la > 0 && isspace(*pa)) + { + la--; + pa++; + } + while (lb > 0 && isspace(*pb)) + { + lb--; + pb++; + } + + /* skip trailing spaces */ + while (la > 0 && isspace(pa[la-1])) + la--; + while (lb > 0 && isspace(pb[lb-1])) + lb--; + + /* compare strings with space normalization */ + while (la > 0 && lb > 0) + { + int ca, cb; + + /* compare character */ + ca = tolower(*pa); + cb = tolower(*pb); + if (ca != cb) + return (ca - cb); + + pa++; pb++; + la--; lb--; + + if (la <= 0 || lb <= 0) + break; + + /* is white space next character ? */ + if (isspace(*pa) && isspace(*pb)) + { + /* skip remaining white spaces */ + while (la > 0 && isspace(*pa)) + { + la--; + pa++; + } + while (lb > 0 && isspace(*pb)) + { + lb--; + pb++; + } + } + } + if (la > 0 || lb > 0) + return la - lb; + + return 0; +} + +int X509_NAME_cmp(const X509_NAME *a, const X509_NAME *b) { int i,j; X509_NAME_ENTRY *na,*nb; @@ -149,10 +266,20 @@ int X509_NAME_cmp(X509_NAME *a, X509_NAME *b) { na=sk_X509_NAME_ENTRY_value(a->entries,i); nb=sk_X509_NAME_ENTRY_value(b->entries,i); - j=na->value->length-nb->value->length; + j=na->value->type-nb->value->type; if (j) return(j); - j=memcmp(na->value->data,nb->value->data, - na->value->length); + if (na->value->type == V_ASN1_PRINTABLESTRING) + j=nocase_spacenorm_cmp(na->value, nb->value); + else if (na->value->type == V_ASN1_IA5STRING + && OBJ_obj2nid(na->object) == NID_pkcs9_emailAddress) + j=nocase_cmp(na->value, nb->value); + else + { + j=na->value->length-nb->value->length; + if (j) return(j); + j=memcmp(na->value->data,nb->value->data, + na->value->length); + } if (j) return(j); j=na->set-nb->set; if (j) return(j); @@ -171,26 +298,17 @@ int X509_NAME_cmp(X509_NAME *a, X509_NAME *b) return(0); } -#ifndef NO_MD5 +#ifndef OPENSSL_NO_MD5 /* I now DER encode the name and hash it. Since I cache the DER encoding, - * this is reasonably effiecent. */ + * this is reasonably efficient. */ unsigned long X509_NAME_hash(X509_NAME *x) { unsigned long ret=0; unsigned char md[16]; - unsigned char str[256],*p,*pp; - int i; - - i=i2d_X509_NAME(x,NULL); - if (i > sizeof(str)) - p=Malloc(i); - else - p=str; - pp=p; - i2d_X509_NAME(x,&pp); - MD5((unsigned char *)p,i,&(md[0])); - if (p != str) Free(p); + /* Make sure X509_NAME structure contains valid cached encoding */ + i2d_X509_NAME(x,NULL); + EVP_Digest(x->bytes->data, x->bytes->length, md, NULL, EVP_md5(), NULL); ret=( ((unsigned long)md[0] )|((unsigned long)md[1]<<8L)| ((unsigned long)md[2]<<16L)|((unsigned long)md[3]<<24L) @@ -207,6 +325,8 @@ X509 *X509_find_by_issuer_and_serial(STACK_OF(X509) *sk, X509_NAME *name, X509_CINF cinf; X509 x,*x509=NULL; + if(!sk) return NULL; + x.cert_info= &cinf; cinf.serialNumber=serial; cinf.issuer=name; @@ -241,6 +361,12 @@ EVP_PKEY *X509_get_pubkey(X509 *x) return(X509_PUBKEY_get(x->cert_info->key)); } +ASN1_BIT_STRING *X509_get0_pubkey_bitstr(const X509 *x) + { + if(!x) return NULL; + return x->cert_info->key->public_key; + } + int X509_check_private_key(X509 *x, EVP_PKEY *k) { EVP_PKEY *xk=NULL; @@ -254,7 +380,7 @@ int X509_check_private_key(X509 *x, EVP_PKEY *k) } switch (k->type) { -#ifndef NO_RSA +#ifndef OPENSSL_NO_RSA case EVP_PKEY_RSA: if (BN_cmp(xk->pkey.rsa->n,k->pkey.rsa->n) != 0 || BN_cmp(xk->pkey.rsa->e,k->pkey.rsa->e) != 0) @@ -264,7 +390,7 @@ int X509_check_private_key(X509 *x, EVP_PKEY *k) } break; #endif -#ifndef NO_DSA +#ifndef OPENSSL_NO_DSA case EVP_PKEY_DSA: if (BN_cmp(xk->pkey.dsa->pub_key,k->pkey.dsa->pub_key) != 0) { @@ -273,7 +399,24 @@ int X509_check_private_key(X509 *x, EVP_PKEY *k) } break; #endif -#ifndef NO_DH +#ifndef OPENSSL_NO_EC + case EVP_PKEY_EC: + { + int r = EC_POINT_cmp(xk->pkey.eckey->group, + xk->pkey.eckey->pub_key,k->pkey.eckey->pub_key,NULL); + if (r != 0) + { + if (r == 1) + X509err(X509_F_X509_CHECK_PRIVATE_KEY, X509_R_KEY_VALUES_MISMATCH); + else + X509err(X509_F_X509_CHECK_PRIVATE_KEY, ERR_R_EC_LIB); + + goto err; + } + } + break; +#endif +#ifndef OPENSSL_NO_DH case EVP_PKEY_DH: /* No idea */ X509err(X509_F_X509_CHECK_PRIVATE_KEY,X509_R_CANT_CHECK_DH_KEY);