LCOV - code coverage report
Current view: top level - zxid - smime-qry.c (source / functions) Hit Total Coverage
Test: ZXID Code Coverage Lines: 16 166 9.6 %
Date: 2010-12-19 Functions: 2 14 14.3 %
Branches: 6 112 5.4 %

           Branch data     Line data    Source code
       1                 :            : /* smime-qry.c  -  Get string representations of various certificate parameters
       2                 :            :  *
       3                 :            :  * Copyright (c) 1999 Sampo Kellomaki <sampo@iki.fi>, All Rights Reserved.
       4                 :            :  * License: This software may be distributed under the same license
       5                 :            :  *          terms as openssl (i.e. free, but mandatory attribution).
       6                 :            :  *
       7                 :            :  * 27.9.1999, Created. --Sampo
       8                 :            :  * 30.9.1999, added PKCS12 stuff, --Sampo
       9                 :            :  * 1.10.1999, improved error reporting, --Sampo
      10                 :            :  * 6.10.1999, forked from keygen.c --Sampo
      11                 :            :  * 9.10.1999, reviewed for double frees --Sampo
      12                 :            :  * 18.10.1999, fixed 256 limit in calls to X509_NAME_oneline() --Sampo
      13                 :            :  */
      14                 :            : 
      15                 :            : #include "platform.h"
      16                 :            : 
      17                 :            : #include <stdio.h>
      18                 :            : #include <string.h>
      19                 :            : #include <time.h>
      20                 :            : 
      21                 :            : #ifdef __MWERKS__
      22                 :            : # include "macglue.h"
      23                 :            : #endif
      24                 :            : 
      25                 :            : #include <openssl/crypto.h>
      26                 :            : #include <openssl/buffer.h>
      27                 :            : #include <openssl/err.h>
      28                 :            : #include <openssl/rand.h>
      29                 :            : #include <openssl/conf.h>
      30                 :            : #include <openssl/bio.h>
      31                 :            : #include <openssl/stack.h>
      32                 :            : #include <openssl/objects.h>
      33                 :            : #include <openssl/asn1.h>
      34                 :            : #include <openssl/pem.h>
      35                 :            : #include <openssl/evp.h>
      36                 :            : #include <openssl/x509.h>
      37                 :            : #include <openssl/x509v3.h>
      38                 :            : #include <openssl/pkcs12.h>
      39                 :            : 
      40                 :            : #define SMIME_INTERNALS  /* we want also our internal helper functions */
      41                 :            : #include "smimeutil.h"
      42                 :            : 
      43                 :            : /* ----------------------- get info ----------------------- */
      44                 :            : 
      45                 :            : /* Obtain some human readable descriptions of the certificate. This is
      46                 :            :  * important, for example, to verify if two certificates have the same
      47                 :            :  * public key modulus.
      48                 :            :  */
      49                 :            : 
      50                 :            : /* Called by:  smime_get_cert_info */
      51                 :            : long  /* return serial number, -1 on failure */
      52                 :            : get_cert_info(X509* x509,
      53                 :            :                     char** modulus,      /* public key modulus */
      54                 :            :                     char** fingerprint)  /* finger print that identifies */
      55                 :          0 : {
      56                 :          0 :   BIO* wbio = NULL;
      57         [ #  # ]:          0 :   if (modulus) *modulus = NULL;
      58         [ #  # ]:          0 :   if (fingerprint) *fingerprint = NULL;
      59         [ #  # ]:          0 :   if (!x509) GOTO_ERR("NULL arg");
      60                 :            : 
      61                 :            :   /* Extract the public key part to be printed on paper */
      62                 :            :   
      63         [ #  # ]:          0 :   if (modulus) {
      64                 :            :     EVP_PKEY* pubkey;
      65         [ #  # ]:          0 :     if (!(wbio = BIO_new(BIO_s_mem()))) GOTO_ERR("no memory?");
      66                 :            :     
      67                 :          0 :     pubkey = X509_get_pubkey(x509);
      68                 :          0 :     BN_print(wbio,pubkey->pkey.rsa->n);
      69         [ #  # ]:          0 :     if (get_written_BIO_data(wbio, modulus) == -1) goto err;
      70                 :          0 :     BIO_free_all(wbio);
      71                 :          0 :     wbio = NULL;
      72                 :            :   }
      73                 :            :   
      74                 :            :   /* Extract conventional message digest */
      75                 :            :   
      76         [ #  # ]:          0 :   if (fingerprint) {
      77                 :            :     unsigned int  md_size;
      78                 :            :     unsigned char md[EVP_MAX_MD_SIZE];
      79         [ #  # ]:          0 :     if (!X509_digest(x509,EVP_md5(),md,&md_size)) GOTO_ERR("X509_digest");
      80         [ #  # ]:          0 :     if (!md_size) goto err;
      81         [ #  # ]:          0 :     if (!(*fingerprint = smime_dotted_hex((char*)md,md_size))) goto err;
      82                 :            :   }  
      83                 :          0 :   return ASN1_INTEGER_get(x509->cert_info->serialNumber);
      84                 :          0 : err:
      85         [ #  # ]:          0 :   if (wbio) BIO_free_all(wbio);
      86                 :          0 :   return -1;
      87                 :            : }
      88                 :            : 
      89                 :            : /* Called by:  main */
      90                 :            : long  /* return serial number, -1 on failure */
      91                 :            : smime_get_cert_info(const char* x509_cert_pem,
      92                 :            :                     char** modulus,      /* public key modulus */
      93                 :            :                     char** fingerprint)  /* finger print that identifies */
      94                 :          0 : {
      95                 :          0 :   long serial = -1;
      96                 :          0 :   X509* x509 = NULL;
      97         [ #  # ]:          0 :   if (modulus) *modulus = NULL;
      98         [ #  # ]:          0 :   if (fingerprint) *fingerprint = NULL;
      99         [ #  # ]:          0 :   if (!(x509 = extract_certificate(x509_cert_pem))) goto err;
     100                 :          0 :   serial = get_cert_info(x509, modulus, fingerprint);
     101                 :            :   
     102                 :          0 : err:
     103         [ #  # ]:          0 :   if (x509) X509_free(x509);
     104                 :          0 :   return serial;
     105                 :            : }
     106                 :            : 
     107                 :            : /* -------------------------------------- */
     108                 :            : 
     109                 :            : /* Called by:  get_req_hash, smime_get_req_modulus */
     110                 :            : char* /* public key modulus */
     111                 :            : get_req_modulus(X509_REQ* req)
     112                 :          0 : {
     113                 :          0 :   char* modulus = NULL;
     114                 :          0 :   BIO* wbio = NULL;  
     115                 :            :   EVP_PKEY* pubkey;
     116                 :            : 
     117         [ #  # ]:          0 :   if (!req) GOTO_ERR("NULL arg");
     118         [ #  # ]:          0 :   if (!(wbio = BIO_new(BIO_s_mem()))) GOTO_ERR("no memory?");
     119                 :            :   
     120                 :            :   /* Extract the public key part to be printed on paper */
     121                 :            :   
     122                 :          0 :   pubkey = X509_REQ_get_pubkey(req);
     123                 :          0 :   BN_print(wbio,pubkey->pkey.rsa->n);
     124         [ #  # ]:          0 :   if (get_written_BIO_data(wbio, &modulus) == -1) goto err;
     125                 :          0 :   BIO_free_all(wbio);
     126                 :          0 :   return modulus;
     127                 :            : 
     128                 :          0 : err:
     129         [ #  # ]:          0 :   if (wbio) BIO_free_all(wbio);
     130                 :          0 :   return NULL;
     131                 :            : }
     132                 :            : 
     133                 :            : /* Called by:  main */
     134                 :            : char* /* public key modulus */
     135                 :            : smime_get_req_modulus(const char* request_pem)
     136                 :          0 : {
     137                 :          0 :   char* modulus = NULL;
     138                 :          0 :   X509_REQ* req = NULL;;
     139         [ #  # ]:          0 :   if (!(req = extract_request(request_pem))) goto err;
     140                 :          0 :   modulus = get_req_modulus(req);
     141                 :            :   
     142                 :          0 : err:
     143         [ #  # ]:          0 :   if (req) X509_REQ_free(req);
     144                 :          0 :   return modulus;
     145                 :            : }
     146                 :            : 
     147                 :            : /* -------------------------------------- */
     148                 :            : 
     149                 :            : /* Calculate a hash over any string (I use it for modulus) */
     150                 :            : 
     151                 :            : /* Called by:  main x2 */
     152                 :            : char*  /* returns the md5 hash as hex dump */
     153                 :            : smime_md5(const char* data)
     154                 :          0 : {
     155                 :            :   EVP_MD_CTX ctx;
     156                 :            :   unsigned int  md_size;
     157                 :            :   unsigned char md[EVP_MAX_MD_SIZE];
     158                 :            :   
     159                 :          0 :   EVP_DigestInit(&ctx,EVP_md5());
     160                 :          0 :   EVP_DigestUpdate(&ctx,data,strlen(data));
     161                 :          0 :   EVP_DigestFinal(&ctx,md,&md_size);
     162                 :          0 :   return smime_hex((char*)md, md_size);
     163                 :            : }
     164                 :            : 
     165                 :            : /* ---------- req hash ----------- */
     166                 :            : 
     167                 :            : /* request hash is a 25 bit hash used for fast (but not necessarily
     168                 :            :  * collision free) identification and database queries. It has so few
     169                 :            :  * bits because it must fit on coarse 3 of 9 bar code. Basically
     170                 :            :  * 25 bits are encoded in 5 characters from alphabet of 32.
     171                 :            : 
     172                 :            : Hashing scheme:
     173                 :            :   MD5(subject_DN . attributes . public_key_modulus) --> produces
     174                 :            :   128 bits (16 bytes). Take first three bytes plus LSB of fourth
     175                 :            :   byte and encode them in base 32.
     176                 :            : 
     177                 :            :   On second thought, if we use two bar codes of 13+2 characters, we can
     178                 :            :   represent full 128 bits of information. This should be considered
     179                 :            :   sufficient even on security grounds. So, take 128 bit MD5 hash, divide
     180                 :            :   it in two blocks of 64 bits (8 bytes). Now, 13*5 = 65, so it takes
     181                 :            :   13 characters to encode each block. Last bit is padded with zero.
     182                 :            : 
     183                 :            : Base 32 encoding:
     184                 :            :   work from LSB to MSB and left to right in groups of 5 bits (5 groups),
     185                 :            :   encode each 5 bit number using
     186                 :            : 
     187                 :            :                      1         2         3
     188                 :            :            01234567890123456789012345678901
     189                 :            :   key ==> "ZY234.6789ABCDEFGHWJKLMNXPQR-TUV" <==
     190                 :            : 
     191                 :            : 
     192                 :            :   Note: Difficult-to-distinguish characters in the sequence have
     193                 :            :         been replaced by less ambiguous ones: 0O1I5S --> ZXYW.-
     194                 :            : 
     195                 :            :   Note: LSB of first 5 bit number is LSB of byte 0. LSB of second 5 bit
     196                 :            :   number is bit 5 of byte 0 and MSB of second number is bit 1 of byte 1.
     197                 :            : 
     198                 :            :   <-- MSB  LSB -->
     199                 :            : 
     200                 :            : Char                                                                       Pad
     201                 :            :  |   byte 0   byte 1   byte 2   byte 3   byte 4   byte 5   byte 6   byte 7   |
     202                 :            :  V   AAAAAAAA BBBBBBBB CCCCCCCC DDDDDDDD EEEEEEEE FFFFFFFF GGGGGGGG HHHHHHHH V
     203                 :            :  0:     43210                          
     204                 :            :  1:  210            43                 
     205                 :            :  2:            43210                   
     206                 :            :  3:           0            4321        
     207                 :            :  4:                    3210     4
     208                 :            :  5:                              43210
     209                 :            :  6:                                   01      423
     210                 :            :  7:                                      43210
     211                 :            :  8:                                                  43210
     212                 :            :  9:                                               210            43
     213                 :            : 10:                                                         43210
     214                 :            : 11:                                                        0            4321
     215                 :            : 12:                                                                 3210     4
     216                 :            : 
     217                 :            : */
     218                 :            : 
     219                 :            : static char req_hash_key[] = "ZY234.6789ABCDEFGHWJKLMNXPQR-TUV";
     220                 :            : 
     221                 :            : /* Called by:  get_req_hash x2 */
     222                 :            : static void
     223                 :            : encode_64bits(unsigned char* md, char*p)
     224                 :          0 : {
     225                 :          0 :   p[0]  = req_hash_key[ md[0] & 0x1f ];
     226                 :          0 :   p[1]  = req_hash_key[ ((md[0] >> 5) & 0x07) | ((md[1] & 0x03) << 3) ];
     227                 :          0 :   p[2]  = req_hash_key[ (md[1] >> 2) & 0x1f ];
     228                 :          0 :   p[3]  = req_hash_key[ ((md[1] >> 7) & 0x01) | ((md[2] & 0x0f) << 1) ];
     229                 :          0 :   p[4]  = req_hash_key[ ((md[2] >> 4) & 0x0f) | ((md[3] & 0x01) << 4) ];
     230                 :          0 :   p[5]  = req_hash_key[ (md[3] >> 1) & 0x1f ];
     231                 :          0 :   p[6]  = req_hash_key[ ((md[3] >> 6) & 0x03) | ((md[4] & 0x07) << 2) ];
     232                 :          0 :   p[7]  = req_hash_key[ (md[4] >> 3) & 0x1f ];
     233                 :          0 :   p[8]  = req_hash_key[ md[5] & 0x1f ];
     234                 :          0 :   p[9]  = req_hash_key[ ((md[5] >> 5) & 0x07) | ((md[6] & 0x03) << 3) ];
     235                 :          0 :   p[10] = req_hash_key[ (md[6] >> 2) & 0x1f ];
     236                 :          0 :   p[11] = req_hash_key[ ((md[6] >> 7) & 0x01) | ((md[7] & 0x0f) << 1) ];
     237                 :          0 :   p[12] = req_hash_key[ ((md[7] >> 4) & 0x0f) /* | bit4 is zero pad */  ];
     238                 :          0 :   p[13] = '\0';
     239                 :          0 : }
     240                 :            : 
     241                 :            : /* Called by: */
     242                 :            : char*  /* hash, ready to print, or NULL if error */
     243                 :            : get_req_hash(X509_REQ* req)
     244                 :          0 : {
     245                 :            :   EVP_MD_CTX ctx;
     246                 :            :   unsigned int  md_size;
     247                 :            :   unsigned char md[EVP_MAX_MD_SIZE];
     248                 :            :   char* p;
     249                 :            : 
     250         [ #  # ]:          0 :   if (!req) GOTO_ERR("NULL arg");
     251                 :            :   
     252                 :          0 :   EVP_DigestInit(&ctx,EVP_md5());
     253                 :            :   
     254         [ #  # ]:          0 :   if (!(p = get_req_name(req))) goto err;
     255                 :          0 :   EVP_DigestUpdate(&ctx,p,strlen(p));
     256                 :          0 :   OPENSSL_free(p);
     257                 :            :   
     258         [ #  # ]:          0 :   if (!(p = get_req_attr(req))) goto err;
     259                 :          0 :   EVP_DigestUpdate(&ctx,p,strlen(p));
     260                 :          0 :   OPENSSL_free(p);
     261                 :            :   
     262         [ #  # ]:          0 :   if (!(p = get_req_modulus(req))) goto err;
     263                 :          0 :   EVP_DigestUpdate(&ctx,p,strlen(p));
     264                 :          0 :   OPENSSL_free(p);
     265                 :            :   
     266                 :          0 :   EVP_DigestFinal(&ctx,md,&md_size);
     267                 :            : 
     268         [ #  # ]:          0 :   if (md_size < 16) goto err;
     269         [ #  # ]:          0 :   if (!(p = (char*)OPENSSL_malloc(13+13+1))) GOTO_ERR("no memory?");
     270                 :            : 
     271                 :          0 :   encode_64bits(md, p);       /* block 1, first 13 chars */
     272                 :          0 :   encode_64bits(md+8, p+13);  /* block 2, second 13 chars */
     273                 :          0 :   return p;
     274                 :            : 
     275                 :          0 : err:
     276                 :          0 :   return NULL;
     277                 :            : }
     278                 :            : 
     279                 :            : char* /* 25 bit hash as string like `*Z4K67W*' or NULL if error */
     280                 :            : smime_get_req_hash(const char* request_pem)
     281                 :          0 : {
     282                 :          0 :   char* n = NULL;
     283                 :          0 :   X509_REQ* req = NULL;
     284         [ #  # ]:          0 :   if (!(req = extract_request(request_pem))) goto err;
     285                 :          0 :   n = get_req_hash(req);
     286                 :            :   
     287                 :          0 : err:
     288         [ #  # ]:          0 :   if (req) X509_REQ_free(req);
     289                 :          0 :   return n;
     290                 :            : }
     291                 :            : 
     292                 :            : /* -------------------------------------- */
     293                 :            : 
     294                 :            : /* Get distinguished name information from the certificate */
     295                 :            : 
     296                 :            : /* Called by:  smime_get_cert_names */
     297                 :            : long  /* return serial number, -1 on failure */
     298                 :            : get_cert_names(X509* x509,
     299                 :            :                char** subject_DN,   /* who the certificate belongs to */
     300                 :            :                char** issuer_DN)    /* who signed the certificate */
     301                 :          0 : {
     302                 :          0 :   long serial = -1;
     303                 :            : 
     304         [ #  # ]:          0 :   if (subject_DN) *subject_DN = NULL;
     305         [ #  # ]:          0 :   if (issuer_DN) *issuer_DN = NULL;
     306         [ #  # ]:          0 :   if (!x509) GOTO_ERR("NULL arg");
     307                 :            :   
     308         [ #  # ]:          0 :   if (subject_DN) {  /* if you don't want to know subject, pass this as NULL */
     309         [ #  # ]:          0 :     if (!(*subject_DN = X509_NAME_oneline(X509_get_subject_name(x509),NULL,0)))
     310                 :          0 :       GOTO_ERR("no memory?");
     311                 :            :   }
     312                 :            :   
     313         [ #  # ]:          0 :   if (issuer_DN) {   /* if you don't want to know issuer, pass NULL here */    
     314         [ #  # ]:          0 :     if (!(*issuer_DN = X509_NAME_oneline(X509_get_issuer_name(x509),NULL,0)))
     315                 :          0 :       GOTO_ERR("no memory?");
     316                 :            :   }
     317                 :            : 
     318                 :            :   /* extract serial number */
     319                 :            : 
     320                 :          0 :   serial = ASN1_INTEGER_get(x509->cert_info->serialNumber);
     321                 :          0 : err:
     322                 :          0 :   return serial;
     323                 :            : }
     324                 :            : 
     325                 :            : /* Called by:  main */
     326                 :            : long  /* return serial number, -1 on failure */
     327                 :            : smime_get_cert_names(const char* x509_cert_pem,
     328                 :            :                      char** subject_DN,   /* who the certificate belongs to */
     329                 :            :                      char** issuer_DN)    /* who signed the certificate */
     330                 :          1 : {
     331                 :          1 :   long serial = -1;
     332                 :          1 :   X509* x509 = NULL;
     333         [ +  - ]:          1 :   if (subject_DN) *subject_DN = NULL;
     334         [ +  - ]:          1 :   if (issuer_DN) *issuer_DN = NULL;
     335         [ -  + ]:          1 :   if (!(x509 = extract_certificate(x509_cert_pem))) goto err;
     336                 :          0 :   serial = get_cert_names(x509, subject_DN, issuer_DN);
     337                 :            :   
     338                 :          1 : err:
     339         [ -  + ]:          1 :   if (x509) X509_free(x509);
     340                 :          1 :   return serial;
     341                 :            : }
     342                 :            : 
     343                 :            : /* -------------------------------------- */
     344                 :            : 
     345                 :            : /* Getting the attributes does not appear to be too well supported, i.e.
     346                 :            :  * there is no easy way. You just have to walk the data structure yourself.
     347                 :            :  * This function only understands sets of one value and single values.
     348                 :            :  * See crypto/asn1/asn1_par.c for similar code. */
     349                 :            : 
     350                 :            : /* Called by:  get_req_hash, smime_get_req_attr */
     351                 :            : char* /* new line separated list of attribute value pairs */
     352                 :            : get_req_attr(X509_REQ* req)
     353                 :          0 : {
     354                 :            :   int i;
     355                 :          0 :   STACK_OF(X509_ATTRIBUTE)* xas = NULL;
     356                 :            :   X509_ATTRIBUTE* xa;
     357                 :            :   ASN1_TYPE* val;
     358                 :          0 :   STACK_OF(ASN1_TYPE)* vals = NULL;
     359                 :          0 :   char* buf = NULL;
     360                 :            :   
     361         [ #  # ]:          0 :   if (!req) GOTO_ERR("NULL arg");
     362         [ #  # ]:          0 :   if (!(buf = strdup(""))) GOTO_ERR("no memory?");
     363         [ #  # ]:          0 :   if ((xas = req->req_info->attributes) == NULL) goto err; /* no attributes */
     364                 :            : 
     365         [ #  # ]:          0 :   for (i = 0; i < sk_X509_ATTRIBUTE_num(xas); i++) {
     366                 :          0 :     xa = sk_X509_ATTRIBUTE_value(xas, i);
     367                 :            :     
     368                 :            :     /* print the (long)name of the attribute */
     369                 :            : 
     370         [ #  # ]:          0 :     if (!(buf = concat(buf, OBJ_nid2ln(OBJ_obj2nid(xa->object))))) goto err;
     371         [ #  # ]:          0 :     if (!(buf = concat(buf, "="))) goto err;
     372                 :            :     
     373                 :            :     /* Obtain either the single value or the first value in the set */
     374                 :            :     
     375                 :            :     if (1 /*|| xa->single  **** this is called set on some versions */) {
     376   [ #  #  #  # ]:          0 :       if ((vals = xa->value.set) && sk_ASN1_TYPE_num(vals)) {
     377                 :          0 :         val = sk_ASN1_TYPE_value(vals,0);
     378                 :            :       } else
     379                 :          0 :         val = NULL;
     380                 :            :     } else {
     381                 :            :       val = xa->value.single;
     382                 :            :     }
     383         [ #  # ]:          0 :     if (val) {
     384                 :            :       /* print the value. *** for now this only works for various string
     385                 :            :          types */
     386         [ #  # ]:          0 :       if (!(buf = concatmem(buf, (char*)(val->value.asn1_string->data),
     387                 :          0 :                             val->value.asn1_string->length))) goto err;
     388                 :            :     }
     389                 :            :     
     390         [ #  # ]:          0 :     if (!(buf = concat(buf,"\n"))) goto err;
     391                 :            :   }
     392                 :          0 :   return buf;
     393                 :          0 : err:
     394                 :          0 :   return NULL;
     395                 :            : }
     396                 :            : 
     397                 :            : /* Called by:  main */
     398                 :            : char* /* public key modulus */
     399                 :            : smime_get_req_attr(const char* request_pem)
     400                 :          0 : {
     401                 :          0 :   char* name = NULL;
     402                 :          0 :   X509_REQ* req = NULL;
     403         [ #  # ]:          0 :   if (!(req = extract_request(request_pem))) goto err;
     404                 :          0 :   name = get_req_attr(req);
     405                 :            :   
     406                 :          0 : err:
     407         [ #  # ]:          0 :   if (req) X509_REQ_free(req);
     408                 :          0 :   return name;
     409                 :            : }
     410                 :            : 
     411                 :            : /* Called by:  get_req_hash, smime_get_req_name */
     412                 :            : char* /* subject_DN - who the request belongs to */
     413                 :            : get_req_name(X509_REQ* req)
     414                 :          0 : {  
     415         [ #  # ]:          0 :   if (!req) GOTO_ERR("NULL arg");
     416                 :          0 :   return X509_NAME_oneline(X509_REQ_get_subject_name(req),NULL,0);
     417                 :          0 : err:
     418                 :          0 :   return NULL;
     419                 :            : }
     420                 :            : 
     421                 :            : /* Called by:  main */
     422                 :            : char* /* public key modulus */
     423                 :            : smime_get_req_name(const char* request_pem)
     424                 :          1 : {
     425                 :          1 :   char* name = NULL;
     426                 :          1 :   X509_REQ* req = NULL;
     427         [ -  + ]:          1 :   if (!(req = extract_request(request_pem))) goto err;
     428                 :          0 :   name = get_req_name(req);
     429                 :            :   
     430                 :          1 : err:
     431         [ -  + ]:          1 :   if (req) X509_REQ_free(req);
     432                 :          1 :   return name;
     433                 :            : }
     434                 :            : 
     435                 :            : /* EOF  -  smime-qry.c */

Generated by: LCOV version 1.9