LCOV - code coverage report
Current view: top level - zxid - zxcrypto.c (source / functions) Hit Total Coverage
Test: ZXID Code Coverage Lines: 285 388 73.5 %
Date: 2010-12-19 Functions: 12 14 85.7 %
Branches: 99 214 46.3 %

           Branch data     Line data    Source code
       1                 :            : /* zxid/zxcrypto.c  -  Glue for cryptographical functions
       2                 :            :  * Copyright (c) 2006-2009 Symlabs (symlabs@symlabs.com), All Rights Reserved.
       3                 :            :  * Author: Sampo Kellomaki (sampo@iki.fi)
       4                 :            :  * This is confidential unpublished proprietary source code of the author.
       5                 :            :  * NO WARRANTY, not even implied warranties. Contains trade secrets.
       6                 :            :  * Distribution prohibited unless authorized in writing.
       7                 :            :  * Licensed under Apache License 2.0, see file COPYING.
       8                 :            :  * $Id: zxcrypto.c,v 1.10 2009-11-24 23:53:40 sampo Exp $
       9                 :            :  *
      10                 :            :  * 7.10.2008, added documentation --Sampo
      11                 :            :  * 29.8.2009, added zxid_mk_self_signed_cert() --Sampo
      12                 :            :  */
      13                 :            : 
      14                 :            : #include "platform.h"  /* needed on Win32 for snprintf() et al. */
      15                 :            : 
      16                 :            : #include <zx/errmac.h>
      17                 :            : #include <zx/zx.h>
      18                 :            : #include <zx/zxid.h>
      19                 :            : #include <zx/zxidutil.h>
      20                 :            : #include <zx/c/zx-sa-data.h>
      21                 :            : #include <string.h>
      22                 :            : #include <sys/stat.h>  /* umask(2) */
      23                 :            : 
      24                 :            : #ifdef USE_OPENSSL
      25                 :            : #include <openssl/evp.h>
      26                 :            : #include <openssl/md5.h>
      27                 :            : #include <openssl/hmac.h>
      28                 :            : #include <openssl/rand.h>
      29                 :            : #include <openssl/x509.h>
      30                 :            : #include <openssl/x509v3.h>
      31                 :            : #include <openssl/rsa.h>
      32                 :            : #include <openssl/pem.h>
      33                 :            : #endif
      34                 :            : 
      35                 :            : #if 0
      36                 :            : /* Called by: */
      37                 :            : struct zx_str* zx_hmac_sha1(struct zx_ctx* c, struct zx_str* key, struct zx_str* ss) {
      38                 :            :   HMAC(EVP_sha1(), key->s, key->len, ss->s, ss->len, md, mdlen);
      39                 :            : 
      40                 :            :   EVP_CIPHER_CTX *ctx;
      41                 :            :   EVP_CIPHER *type = EVP_des_cbc();
      42                 :            : 
      43                 :            :   int EVP_SealInit(ctx, type, char **ek, int *ekl, char *iv, EVP_PKEY **pubk, int npubk);
      44                 :            :   int EVP_SealUpdate(ctx, unsigned char *out, int *outl, unsigned char *in, int inl);
      45                 :            :   int EVP_SealFinal(ctx, unsigned char *out, int *outl);  
      46                 :            : }
      47                 :            : 
      48                 :            : /* Following are macros in openssl headers so we need to define wrapper functions. */
      49                 :            : 
      50                 :            : /* Called by: */
      51                 :            : int zx_EVP_CIPHER_key_length(const EVP_CIPHER* cipher) { return EVP_CIPHER_key_length(cipher); }
      52                 :            : int zx_EVP_CIPHER_iv_length(const EVP_CIPHER* cipher)  { return EVP_CIPHER_iv_length(cipher); }
      53                 :            : int zx_EVP_CIPHER_block_size(const EVP_CIPHER* cipher) { return EVP_CIPHER_block_size(cipher); }
      54                 :            : #endif
      55                 :            : 
      56                 :            : /*() zx_raw_digest2() computes a message digest over two items. The result
      57                 :            :  * is placed in buffer md, which must already be of length sufficient for
      58                 :            :  * the digest. md will not be nul terminated (and will usually have binary
      59                 :            :  * data). Possible algos: SHA1 */
      60                 :            : 
      61                 :            : char* zx_raw_digest2(struct zx_ctx* c, char* md, char* const algo, int len, const char* s, int len2, const char* s2)
      62                 :         74 : {
      63                 :         74 :   char* where = "start";
      64                 :            :   const EVP_MD* evp_digest;
      65                 :            :   EVP_MD_CTX ctx;
      66                 :         74 :   OpenSSL_add_all_digests();
      67                 :         74 :   EVP_MD_CTX_init(&ctx);
      68                 :         74 :   evp_digest = EVP_get_digestbyname(algo);
      69         [ -  + ]:         74 :   if (!evp_digest) {
      70                 :          0 :     ERR("Digest algo name(%s) not recognized by the crypto library (OpenSSL)", algo);
      71                 :          0 :     return 0;
      72                 :            :   }
      73                 :            :     
      74         [ -  + ]:         74 :   if (!EVP_DigestInit_ex(&ctx, evp_digest, 0 /* engine */)) {
      75                 :          0 :     where = "EVP_DigestInit_ex()";
      76                 :          0 :     goto sslerr;
      77                 :            :   }
      78                 :            :   
      79   [ +  -  +  - ]:         74 :   if (len && s) {
      80         [ -  + ]:         74 :     if (!EVP_DigestUpdate(&ctx, s, len)) {
      81                 :          0 :       where = "EVP_DigestUpdate()";
      82                 :          0 :       goto sslerr;
      83                 :            :     }
      84                 :            :   }
      85                 :            :   
      86   [ +  -  +  - ]:         74 :   if (len2 && s2) {
      87         [ -  + ]:         74 :     if (!EVP_DigestUpdate(&ctx, s2, len2)) {
      88                 :          0 :       where = "EVP_DigestUpdate() 2";
      89                 :          0 :       goto sslerr;
      90                 :            :     }
      91                 :            :   }
      92                 :            :   
      93         [ -  + ]:         74 :   if(!EVP_DigestFinal_ex(&ctx, (unsigned char*)md, 0)) {
      94                 :          0 :     where = "EVP_DigestFinal_ex()";
      95                 :          0 :     goto sslerr;
      96                 :            :   }
      97                 :         74 :   EVP_MD_CTX_cleanup(&ctx);
      98                 :         74 :   return md;
      99                 :            : 
     100                 :          0 :  sslerr:
     101                 :          0 :   zx_report_openssl_error(where);
     102                 :          0 :   EVP_MD_CTX_cleanup(&ctx);
     103                 :          0 :   return 0;
     104                 :            : }
     105                 :            : 
     106                 :            : /*() zx_EVP_DecryptFinal_ex() is a drop-in replacement for OpenSSL EVP_DecryptFinal_ex.
     107                 :            :  * It performs XML Enc compatible padding check.  See OpenSSL bug 1067
     108                 :            :  * http://rt.openssl.org/Ticket/Display.html?user=guest&;pass=guest&id=1067 */
     109                 :            : 
     110                 :            : /* Called by:  zx_raw_cipher */
     111                 :        105 : int zx_EVP_DecryptFinal_ex(EVP_CIPHER_CTX *ctx, unsigned char *out, int *outl) {
     112                 :            :   int i,n;
     113                 :            :   unsigned int b;
     114                 :            :   
     115                 :        105 :   *outl=0;
     116                 :        105 :   b=ctx->cipher->block_size;
     117         [ +  - ]:        105 :   if (b > 1) {
     118   [ +  -  -  + ]:        105 :     if (ctx->buf_len || !ctx->final_used) {
     119                 :            :       //EVPerr(EVP_F_EVP_DECRYPTFINAL_EX,EVP_R_WRONG_FINAL_BLOCK_LENGTH);
     120                 :          0 :       return(0);
     121                 :            :     }
     122   [ -  +  #  # ]:        105 :     ASSERTOP(b, <=, sizeof ctx->final);
     123                 :        105 :     n=ctx->final[b-1];
     124   [ +  -  +  + ]:        105 :     if (n == 0 || n > (int)b) {
     125                 :            :       //EVPerr(EVP_F_EVP_DECRYPTFINAL_EX,EVP_R_BAD_DECRYPT);
     126                 :          2 :       return(0);
     127                 :            :     }
     128                 :            :       
     129                 :            :     /* The padding used in XML Enc does not follow RFC 1423
     130                 :            :      * and is not supported by OpenSSL. The last padding byte
     131                 :            :      * is checked, but all other padding bytes are ignored
     132                 :            :      * and trimmed.
     133                 :            :      *
     134                 :            :      * [XMLENC] D. Eastlake, ed., XML Encryption Syntax and
     135                 :            :      * Processing, W3C Recommendation 10. Dec. 2002,
     136                 :            :      * www.w3.org/TR/2002/REC-xmlenc-core-20021210">http://www.w3.org/TR/2002/REC-xmlenc-core-20021210 */
     137         [ -  + ]:        103 :     if (ctx->final[b-1] != n) {
     138                 :            :       //EVPerr(EVP_F_EVP_DECRYPTFINAL_EX,EVP_R_BAD_DECRYPT);
     139                 :          0 :       return(0);
     140                 :            :     }
     141                 :        103 :     n=ctx->cipher->block_size-n;
     142         [ +  + ]:        758 :     for (i=0; i<n; i++)
     143                 :        655 :       out[i]=ctx->final[i];
     144                 :        103 :     *outl=n;
     145                 :            :   } else
     146                 :          0 :     *outl=0;
     147                 :        103 :   return 1;
     148                 :            : }
     149                 :            : 
     150                 :            : //#define ZX_DEFAULT_IV "012345678901234567890123456789012345678901234567890123456789" /* 60 */
     151                 :            : #define ZX_DEFAULT_IV   "ZX_DEFAULT_IV ZXID.ORG SAML 2.0 and Liberty ID-WSF by Sampo." /* 60 */
     152                 :            : 
     153                 :            : /*() zx_raw_cipher() can encrypt and decrypt, based on encflag, using symmetic cipher algo.
     154                 :            :  * If encflag (==1) indicates encryption, the initialization vector will be prepended. */
     155                 :            : 
     156                 :            : /* Called by:  zxenc_symkey_dec x4, zxenc_symkey_enc, zxid_psobj_dec, zxid_psobj_enc */
     157                 :            : struct zx_str* zx_raw_cipher(struct zx_ctx* c, const char* algo, int encflag, struct zx_str* key, int len, const char* s, int iv_len, const char* iv)
     158                 :       1134 : {
     159                 :            :   const char* ivv;
     160                 :       1134 :   char* where = "start";
     161                 :            :   struct zx_str* out;
     162                 :            :   int outlen, tmplen, alloclen;
     163                 :            :   const EVP_CIPHER* evp_cipher;
     164                 :            :   EVP_CIPHER_CTX ctx;
     165                 :       1134 :   OpenSSL_add_all_algorithms();
     166                 :       1134 :   EVP_CIPHER_CTX_init(&ctx);
     167                 :       1134 :   evp_cipher = EVP_get_cipherbyname(algo);
     168         [ -  + ]:       1134 :   if (!evp_cipher) {
     169                 :          0 :     ERR("Cipher algo name(%s) not recognized by the crypto library (OpenSSL)", algo);
     170                 :          0 :     return 0;
     171                 :            :   }
     172                 :            :   
     173                 :       1134 :   tmplen = EVP_CIPHER_iv_length(evp_cipher);
     174         [ +  - ]:       1134 :   if (tmplen) {
     175         [ +  + ]:       1134 :     if (iv) {
     176         [ -  + ]:        105 :       if (iv_len != tmplen) {
     177                 :          0 :         goto clean;
     178                 :            :       }
     179                 :        105 :       ivv = iv;
     180                 :            :     } else {
     181                 :       1029 :       ivv = ZX_DEFAULT_IV;
     182                 :            :       ASSERTOP(EVP_MAX_IV_LENGTH, <=, sizeof(ZX_DEFAULT_IV));
     183                 :            :     }
     184                 :            :   } else
     185                 :          0 :     ivv = 0;
     186                 :            :   
     187                 :       1134 :   alloclen = EVP_CIPHER_block_size(evp_cipher);
     188                 :       1134 :   alloclen = len + alloclen + alloclen;  /* bit pessimistic, but man EVP_CipherInit is ambiguous about the actual size needed. */
     189         [ +  + ]:       1134 :   if (encflag)
     190                 :       1029 :     alloclen += iv_len;
     191                 :            :   
     192                 :       1134 :   out = zx_new_len_str(c, alloclen);
     193         [ +  - ]:       1134 :   if (!out) goto clean;
     194         [ +  + ]:       1134 :   if (encflag)
     195                 :       1029 :     memcpy(out->s, ivv, iv_len);
     196                 :            :   else
     197                 :        105 :     iv_len = 0;  /* When decrypting, the iv has already been stripped. */
     198                 :            :   
     199         [ -  + ]:       1134 :   if (!EVP_CipherInit_ex(&ctx, evp_cipher, 0 /* engine */, (unsigned char*)key->s, (unsigned char*)ivv, encflag)) {
     200                 :          0 :     where = "EVP_CipherInit_ex()";
     201                 :          0 :     goto sslerr;
     202                 :            :   }
     203                 :            :   
     204         [ -  + ]:       1134 :   if (!EVP_CIPHER_CTX_set_key_length(&ctx, key->len)) {
     205                 :          0 :     where = "wrong key length for algorithm (block ciphers only accept keys of determined length)";
     206                 :          0 :     goto sslerr;
     207                 :            :   }
     208                 :            :   
     209         [ -  + ]:       1134 :   if (!EVP_CipherUpdate(&ctx, (unsigned char*)out->s + iv_len, &outlen, (unsigned char*)s, len)) { /* Actual crypto happens here */
     210                 :          0 :     where = "EVP_CipherUpdate()";
     211                 :          0 :     goto sslerr;
     212                 :            :   }
     213                 :            :   
     214   [ -  +  #  # ]:       1134 :   ASSERTOP(outlen + iv_len, <=, alloclen);
     215                 :            : 
     216                 :            : #if 0  
     217                 :            :   if(!EVP_CipherFinal_ex(&ctx, (unsigned char*)out->s + iv_len + outlen, &tmplen)) {  /* Append final block */
     218                 :            :     where = "EVP_CipherFinal_ex()";
     219                 :            :     goto sslerr;
     220                 :            :   }
     221                 :            : #else
     222                 :            :   /* Patch from Eric Rybski <rybskej@yahoo.com> */
     223         [ +  + ]:       1134 :   if (encflag) {
     224         [ -  + ]:       1029 :     if(!EVP_CipherFinal_ex(&ctx, (unsigned char*)out->s + iv_len + outlen, &tmplen)) { /* Append final block */
     225                 :          0 :       where = "EVP_CipherFinal_ex()";
     226                 :          0 :       goto sslerr;
     227                 :            :     }
     228                 :            :   } else {
     229                 :            :     /* Perform our own padding check, as XML Enc is not guaranteed compatible
     230                 :            :      * with OpenSSL & RFC 1423. See OpenSSL bug 1067
     231                 :            :      * http://rt.openssl.org/Ticket/Display.html?user=guest&;pass=guest&id=1067 */
     232                 :        105 :     EVP_CIPHER_CTX_set_padding(&ctx, 0);
     233         [ +  + ]:        105 :     if(!zx_EVP_DecryptFinal_ex(&ctx, (unsigned char*)out->s + iv_len + outlen, &tmplen)) { /* Append final block */
     234                 :          2 :       where = "zx_EVP_DecryptFinal_ex()";
     235                 :          2 :       goto sslerr;
     236                 :            :     }
     237                 :            :   }
     238                 :            : #endif
     239                 :       1132 :   EVP_CIPHER_CTX_cleanup(&ctx);
     240                 :            :   
     241                 :       1132 :   outlen += tmplen;
     242   [ -  +  #  # ]:       1132 :   ASSERTOP(outlen + iv_len, <=, alloclen);
     243                 :       1132 :   out->len = outlen + iv_len;
     244                 :       1132 :   out->s[outlen + iv_len] = 0;  /* nul term */
     245                 :       1132 :   return out;
     246                 :            : 
     247                 :          2 :  sslerr:
     248                 :          2 :   zx_report_openssl_error(where);
     249                 :          2 :  clean:
     250                 :          2 :   EVP_CIPHER_CTX_cleanup(&ctx);
     251                 :          2 :   return 0;
     252                 :            : }
     253                 :            : 
     254                 :            : /*() RSA public key encryption. See zx_get_rsa_pub_from_cert() for
     255                 :            :  * a way to obtain public key data structure.
     256                 :            :  * N.B. This function +only+ does the public key part. It does not
     257                 :            :  * perform combined enc-session-key-with-pub-key-and-then-data-with-session-key
     258                 :            :  * operation, though this function could be used as a component to implement
     259                 :            :  * such a system.
     260                 :            :  *
     261                 :            :  * This is considered a low level function. See zxenc_pubkey_enc() for a higher level solution. */
     262                 :            : 
     263                 :            : /* Called by:  zxenc_pubkey_enc x2 */
     264                 :            : struct zx_str* zx_rsa_pub_enc(struct zx_ctx* c, struct zx_str* plain, RSA* rsa_pkey, int pad)
     265                 :        957 : {
     266                 :            :   struct zx_str* ciphered;
     267                 :        957 :   int ret, siz = RSA_size(rsa_pkey);
     268   [ +  -  -  - ]:        957 :   switch (pad) {
     269                 :            :   case RSA_PKCS1_PADDING:
     270                 :            :   case RSA_SSLV23_PADDING:
     271         [ -  + ]:        957 :     if (plain->len > (siz-11))
     272                 :          0 :       ERR("Too much data for RSA key: can=%d, you have %d bytes.\n", siz-11, plain->len);
     273   [ +  +  -  + ]:        957 :     D("RSA_PKCS1_PADDING %d", pad);
     274                 :        957 :     break;
     275                 :            :   case RSA_NO_PADDING:
     276         [ #  # ]:          0 :     if (plain->len > siz)
     277                 :          0 :       ERR("Too much data for RSA key: can=%d, you have %d bytes.\n", siz, plain->len);
     278                 :          0 :     break;
     279                 :            :   case RSA_PKCS1_OAEP_PADDING:
     280         [ #  # ]:          0 :     if (plain->len > (siz-41))
     281                 :          0 :       ERR("Too much data for RSA key: can=%d, you have %d bytes.\n", siz-41, plain->len);
     282                 :          0 :     break;
     283   [ #  #  #  # ]:          0 :   default: D("Illegal padding(%d). See `man 3 rsa'\n",pad);
     284                 :            :   }
     285                 :            : 
     286                 :        957 :   ciphered = zx_new_len_str(c, siz);
     287         [ -  + ]:        957 :   if (!ciphered)
     288                 :          0 :     return 0;
     289                 :        957 :   ret = RSA_public_encrypt(plain->len, (unsigned char*)plain->s, (unsigned char*)ciphered->s, rsa_pkey, pad);
     290         [ -  + ]:        957 :   if (siz != ret) {
     291   [ #  #  #  # ]:          0 :     D("RSA pub enc wrong ret=%d siz=%d\n",ret,siz);
     292                 :          0 :     zx_report_openssl_error("zx_pub_encrypt_rsa fail (${ret})");
     293                 :          0 :     return 0;
     294                 :            :   }
     295   [ -  +  #  # ]:        957 :   ASSERTOP(ret, <=, siz);
     296                 :        957 :   ciphered->len = ret;
     297                 :        957 :   ciphered->s[ret] = 0;
     298                 :        957 :   return ciphered;
     299                 :            : }
     300                 :            : 
     301                 :            : /*() RSA public key decryption. See zx_get_rsa_pub_from_cert() for
     302                 :            :  * a way to obtain public key data structure. */
     303                 :            : 
     304                 :            : /* Called by: */
     305                 :            : struct zx_str* zx_rsa_pub_dec(struct zx_ctx* c, struct zx_str* ciphered, RSA* rsa_pkey, int pad)
     306                 :          0 : {
     307                 :            :   struct zx_str* plain;
     308                 :          0 :   int ret, siz = RSA_size(rsa_pkey);
     309                 :          0 :   plain = zx_new_len_str(c, siz);
     310         [ #  # ]:          0 :   if (!plain)
     311                 :          0 :     return 0;
     312                 :          0 :   ret = RSA_public_decrypt(ciphered->len, (unsigned char*)ciphered->s, (unsigned char*)plain->s, rsa_pkey, pad);
     313         [ #  # ]:          0 :   if (ret == -1) {
     314   [ #  #  #  # ]:          0 :     D("RSA public decrypt failed ret=%d len_cipher_data=%d",ret,ciphered->len);
     315                 :          0 :     zx_report_openssl_error("zx_public_decrypt_rsa fail");
     316                 :          0 :     return 0;
     317                 :            :   }
     318   [ #  #  #  # ]:          0 :   ASSERTOP(ret, <=, siz);
     319                 :          0 :   plain->len = ret;
     320                 :          0 :   plain->s[ret] = 0;
     321                 :          0 :   return plain;
     322                 :            : }
     323                 :            : 
     324                 :            : /*() RSA private key decryption. See zxid_read_private_key() and zxid_extract_private_key()
     325                 :            :  * for ways to read in the private key data structure.
     326                 :            :  * N.B. This function +only+ does the private key part. It does not
     327                 :            :  * perform combined dec-session-key-with-priv-key-and-then-data-with-session-key
     328                 :            :  * operation, though this function could be used as a component to implement
     329                 :            :  * such a system.
     330                 :            :  *
     331                 :            :  * This is considered a low level function. See zxenc_privkey_dec() for a higher level solution. */
     332                 :            : 
     333                 :            : /* Called by:  zxenc_privkey_dec x2 */
     334                 :            : struct zx_str* zx_rsa_priv_dec(struct zx_ctx* c, struct zx_str* ciphered, RSA* rsa_pkey, int pad)
     335                 :        103 : {
     336                 :            :   struct zx_str* plain;
     337                 :        103 :   int ret, siz = RSA_size(rsa_pkey);
     338                 :        103 :   plain = zx_new_len_str(c, siz);
     339         [ -  + ]:        103 :   if (!plain)
     340                 :          0 :     return 0;
     341                 :        103 :   ret = RSA_private_decrypt(ciphered->len, (unsigned char*)ciphered->s, (unsigned char*)plain->s, rsa_pkey, pad);
     342         [ -  + ]:        103 :   if (ret == -1) {
     343   [ #  #  #  # ]:          0 :     D("RSA private decrypt failed ret=%d len_cipher_data=%d",ret,ciphered->len);
     344                 :          0 :     zx_report_openssl_error("zx_priv_decrypt_rsa fail");
     345                 :          0 :     return 0;
     346                 :            :   }
     347   [ -  +  #  # ]:        103 :   ASSERTOP(ret, <=, siz);
     348                 :        103 :   plain->len = ret;
     349                 :        103 :   plain->s[ret] = 0;
     350                 :        103 :   return plain;
     351                 :            : }
     352                 :            : 
     353                 :            : /*() RSA private key encryption. See zxid_read_private_key() and zxid_extract_private_key()
     354                 :            :  * for ways to read in the private key data structure. */
     355                 :            : 
     356                 :            : /* Called by: */
     357                 :            : struct zx_str* zx_rsa_priv_enc(struct zx_ctx* c, struct zx_str* plain, RSA* rsa_pkey, int pad)
     358                 :          0 : {
     359                 :            :   struct zx_str* ciphered;
     360                 :          0 :   int ret, siz = RSA_size(rsa_pkey);
     361                 :          0 :   ciphered = zx_new_len_str(c, siz);
     362         [ #  # ]:          0 :   if (!ciphered)
     363                 :          0 :     return 0;
     364                 :          0 :   ret = RSA_private_encrypt(plain->len, (unsigned char*)plain->s, (unsigned char*)ciphered->s, rsa_pkey, pad);
     365         [ #  # ]:          0 :   if (ret == -1) {
     366   [ #  #  #  # ]:          0 :     D("RSA private encrypt failed ret=%d len_plain=%d", ret, plain->len);
     367                 :          0 :     zx_report_openssl_error("zx_priv_encrypt_rsa fail");
     368                 :          0 :     return 0;
     369                 :            :   }
     370   [ #  #  #  # ]:          0 :   ASSERTOP(ret, <=, siz);
     371                 :          0 :   ciphered->len = ret;
     372                 :          0 :   ciphered->s[ret] = 0;
     373                 :          0 :   return ciphered;
     374                 :            : }
     375                 :            : 
     376                 :            : /*() Obtain RSA public key from X509 certificate. The certificate must have been
     377                 :            :  * previously read into a data structure. See zxid_read_cert() and zxid_extract_cert() */
     378                 :            : 
     379                 :            : /* Called by:  zxenc_pubkey_enc, zxlog_write_line */
     380                 :            : RSA* zx_get_rsa_pub_from_cert(X509* cert, char* logkey)
     381                 :        960 : {
     382                 :            :   EVP_PKEY* evp_pkey;
     383                 :            :   struct rsa_st* rsa_pkey;
     384                 :        960 :   evp_pkey = X509_get_pubkey(cert);
     385         [ -  + ]:        960 :   if (!evp_pkey) {
     386                 :          0 :     ERR("RSA enc: failed to get public key from certificate (perhaps you have not supplied any certificate, or it is corrupt or of wrong type) %s", logkey);
     387                 :          0 :     zx_report_openssl_error("zx_get_rsa_pub_from_cert");
     388                 :          0 :     return 0;
     389                 :            :   }
     390                 :        960 :   rsa_pkey = EVP_PKEY_get1_RSA(evp_pkey);
     391         [ -  + ]:        960 :   if (!rsa_pkey) {
     392                 :          0 :     ERR("RSA enc: failed to extract RSA get public key from certificate (perhaps you have not supplied any certificate, or it is corrupt or of wrong type) %s", logkey);
     393                 :          0 :     zx_report_openssl_error("zx_get_rsa_pub_from_cert");
     394                 :          0 :     return 0;
     395                 :            :   }
     396                 :        960 :   return rsa_pkey;
     397                 :            : }
     398                 :            : 
     399                 :            : /*() ZXID centralized hook for obtaning randin numbers. This backends to
     400                 :            :  * OpenSSL random number gnerator and seeds from /dev/urandom where
     401                 :            :  * available. If you want to use /dev/random, which may block, you need
     402                 :            :  * to recompile with ZXID_TRUE_RAND set to true. */
     403                 :            : 
     404                 :            : /* Called by:  main x2, zx_get_symkey, zxenc_pubkey_enc, zxid_mk_at_cert, zxid_mk_id, zxid_mk_id_attr, zxid_mk_self_sig_cert, zxlog_alloc_zbuf, zxlog_write_line */
     405                 :            : void zx_rand(char* buf, int n_bytes)
     406                 :       2803 : {
     407                 :            : #ifdef USE_OPENSSL
     408                 :            : #if ZXID_TRUE_RAND
     409                 :            :   RAND_bytes(buf, n_bytes);
     410                 :            : #else
     411                 :       2803 :   RAND_pseudo_bytes((unsigned char*)buf, n_bytes);
     412                 :            : #endif
     413                 :            : #else
     414                 :            :   ERR("ZXID was compiled without USE_OPENSSL. This means random number generation facilities are unavailable. Recompile ZXID or acknowledge that there is no security. n_rand_bytes=%d", n);
     415                 :            : #endif
     416                 :       2803 : }
     417                 :            : 
     418                 :            : /* Called by:  zxid_mk_at_cert x10, zxid_mk_self_sig_cert x6 */
     419                 :            : static void zxid_add_name_field(X509_NAME* subj, int typ, int nid, char* val)
     420                 :       3693 : {
     421                 :            :   X509_NAME_ENTRY* ne;
     422   [ +  -  -  + ]:       3693 :   if (!val || !*val)
     423                 :          0 :     return;
     424                 :       3693 :   ne = X509_NAME_ENTRY_create_by_NID(0, nid, typ, (unsigned char*)val, strlen(val));
     425                 :       3693 :   X509_NAME_add_entry(subj, ne, X509_NAME_entry_count(subj), 0);
     426                 :            : }
     427                 :            : 
     428                 :            : /*() Create Self-Signed Certificate-Private Key pair and Certificate Signing Request
     429                 :            :  * This function is invoked when AUTO_CERT is set and a certificate is missing.
     430                 :            :  * As this is not expected to be frequent, we are cavalier about releasing
     431                 :            :  * the memory needed for each intermediate step.
     432                 :            :  *
     433                 :            :  * cf:: zxid configuration object, of which cf->ctx will be used for memory allocation
     434                 :            :  * buflen:: sizeof(buf)
     435                 :            :  * buf:: Buffer used for rendering pem representations of the certificate
     436                 :            :  * log key:: Who and why is calling
     437                 :            :  * name:: Name of the certificate file to be created
     438                 :            :  * returns:: 0 on failure, 1 on success
     439                 :            :  *
     440                 :            :  * See also: keygen() in keygen.c */
     441                 :            : 
     442                 :            : /* Called by:  zxid_read_cert, zxid_read_private_key */
     443                 :            : int zxid_mk_self_sig_cert(zxid_conf* cf, int buflen, char* buf, const char* lk, const char* name)
     444                 :          2 : {
     445                 :            : #ifdef USE_OPENSSL
     446                 :            :   BIO* wbio_cert;
     447                 :            :   BIO* wbio_pkey;
     448                 :            :   BIO* wbio_csr;
     449                 :            :   int len, lenq, um;
     450                 :            :   long cert_ser;
     451                 :            :   char*     p;
     452                 :            :   char*     q;
     453                 :            :   time_t    ts;
     454                 :            :   X509*     x509ss;
     455                 :            :   X509_REQ* req;
     456                 :            :   X509_REQ_INFO* ri;
     457                 :            :   EVP_PKEY* pkey;
     458                 :            :   EVP_PKEY* tmp_pkey;
     459                 :            :   RSA*      rsa;
     460                 :            :   X509_EXTENSION*  ext;
     461                 :            :   char      cn[256];
     462                 :            :   char      ou[256];
     463                 :            : 
     464                 :          2 :   X509V3_add_standard_extensions();
     465                 :            :   
     466   [ -  +  #  # ]:          2 :   D("keygen start lk(%s) name(%s)", lk, name);
     467                 :            : 
     468                 :          2 :   p = strstr(cf->url, "://");
     469         [ +  - ]:          2 :   if (p) {
     470                 :          2 :     p += sizeof("://")-1;
     471                 :          2 :     len = strcspn(p, ":/");
     472         [ -  + ]:          2 :     if (len > sizeof(cn)-2)
     473                 :          0 :       len = sizeof(cn)-2;
     474                 :          2 :     memcpy(cn, p, len);
     475                 :          2 :     cn[len] = 0;
     476                 :            :   } else {
     477                 :          0 :     strcpy(cn, "Unknown server cn. Misconfiguration.");
     478                 :            :   }
     479                 :            :   
     480                 :          2 :   snprintf(ou, sizeof(ou)-1, "SSO Dept ZXID Auto-Cert %s", cf->url);
     481                 :          2 :   ou[sizeof(ou)-1] = 0;  /* must terminate manually as on win32 termination is not guaranteed */
     482                 :            : 
     483                 :          2 :   ts = time(0);
     484                 :          2 :   RAND_seed(&ts,sizeof(ts));
     485                 :            : #ifdef WINDOWS
     486                 :            :   RAND_screen(); /* Loading video display memory into random state */
     487                 :            : #endif
     488                 :            :   
     489                 :            :   /* Here's the beef: Generate keypair */
     490                 :            :   
     491                 :          2 :   pkey=EVP_PKEY_new();
     492                 :            :   DD("keygen preparing rsa key %s", lk);
     493                 :          2 :   rsa = RSA_generate_key(1024 /*bits*/, 0x10001 /*65537*/, 0 /*req_cb*/, 0 /*arg*/);
     494                 :            :   DD("keygen rsa key generated %s", name);
     495                 :          2 :   EVP_PKEY_assign_RSA(pkey, rsa);
     496                 :            : 
     497                 :            : #if 0
     498                 :            :   /* Key generation is a big operation. Write in the new random state. */
     499                 :            :   t = time(0);
     500                 :            :   RAND_seed(&t,sizeof(t));
     501                 :            :   RAND_write_file(randomfile);
     502                 :            : #endif
     503                 :            : 
     504                 :            :   /* Now handle the public key part, i.e. create self signed and
     505                 :            :    * certificate request. This starts by making a request that
     506                 :            :    * contains all relevant fields.   */
     507                 :            :   
     508                 :          2 :   req=X509_REQ_new();
     509                 :          2 :   ri=req->req_info;
     510                 :            : 
     511                 :            :   DD("keygen populate: set version %d (real vers is one higher)", 2);
     512                 :          2 :   ASN1_INTEGER_set(ri->version, 2L /* version 3 (binary value is one less) */);
     513                 :            : 
     514                 :            : #if 0 /* See cn code above */
     515                 :            :   /* Parse domain name out of the URL: skip https:// and then scan name without port or path */
     516                 :            :   
     517                 :            :   for (p = cf->url; !ONE_OF_2(*p, '/', 0); ++p) ;
     518                 :            :   if (*p != '/') goto badurl;
     519                 :            :   ++p;
     520                 :            :   if (*p != '/') {
     521                 :            : badurl:
     522                 :            :     ERR("Malformed URL: does not start by https:// or http:// -- URL(%s)", cf->url);
     523                 :            :     return 0;
     524                 :            :   }
     525                 :            :   ++p;
     526                 :            :   for (q = cn; !ONE_OF_3(*p, ':', '/', 0) && q < cn + sizeof(cn)-1; ++q, ++p) *q = *p;
     527                 :            :   *q = 0;
     528                 :            : 
     529                 :            :   D("keygen populate DN: cn(%s) org(%s) c(%s) url=%p cn=%p p=%p q=%p", cn, cf->org_name, cf->country, cf->url, cn, p, q);
     530                 :            : #endif
     531                 :            : 
     532                 :            :   /* Note on string types and allowable char sets:
     533                 :            :    * V_ASN1_PRINTABLESTRING  [A-Za-z0-9 '()+,-./:=?]   -- Any domain name, but not query string
     534                 :            :    * V_ASN1_IA5STRING        Any 7bit string
     535                 :            :    * V_ASN1_T61STRING        8bit string   */
     536                 :            : 
     537                 :            :   /* Construct DN part by part. We want cn=www.site.com,o=ZXID Auto-Cert */
     538                 :            : 
     539                 :          2 :   zxid_add_name_field(ri->subject, V_ASN1_PRINTABLESTRING, NID_commonName, cn);
     540                 :          2 :   zxid_add_name_field(ri->subject, V_ASN1_T61STRING, NID_organizationalUnitName, ou);
     541                 :          2 :   zxid_add_name_field(ri->subject, V_ASN1_T61STRING, NID_organizationName, cf->org_name);
     542                 :            : 
     543                 :          2 :   zxid_add_name_field(ri->subject, V_ASN1_T61STRING, NID_localityName, cf->locality);
     544                 :          2 :   zxid_add_name_field(ri->subject, V_ASN1_T61STRING, NID_stateOrProvinceName, cf->state);
     545                 :          2 :   zxid_add_name_field(ri->subject, V_ASN1_T61STRING, NID_countryName, cf->country);
     546                 :            : 
     547                 :            : #if 0
     548                 :            :   X509_ATTRIBUTE*  xa;
     549                 :            :   ASN1_BIT_STRING* bs;
     550                 :            :   ASN1_TYPE* at;
     551                 :            : 
     552                 :            :   /* It seems this gives indigestion to the default CA */
     553                 :            :   DD("keygen populate attributes %s", lk);  /* Add attributes: we really only need cn */
     554                 :            :   
     555                 :            :   xa = X509_ATTRIBUTE_new();
     556                 :            :   xa->value.set = sk_ASN1_TYPE_new_null();
     557                 :            :   /*xa->single = 1; **** this may also be set on some versions */
     558                 :            :   xa->object=OBJ_nid2obj(NID_commonName);
     559                 :            : 
     560                 :            :   bs = ASN1_BIT_STRING_new();
     561                 :            :   bs->type = V_ASN1_PRINTABLESTRING;
     562                 :            :   ASN1_STRING_set(bs, cn, strlen(cn)+1);  /* *** +1 why? Some archaic bug work-around? */
     563                 :            : 
     564                 :            :   at = ASN1_TYPE_new();
     565                 :            :   ASN1_TYPE_set(at, bs->type, (char*)bs);
     566                 :            :   sk_ASN1_TYPE_push(xa->value.set, at);
     567                 :            :   sk_X509_ATTRIBUTE_push(ri->attributes, xa);
     568                 :            : #endif
     569                 :            : 
     570                 :            :   DD("keygen request populated %s", lk);
     571                 :          2 :   X509_REQ_set_pubkey(req, pkey);
     572                 :            :   /*req->req_info->req_kludge=0;    / * no asn1 kludge *** filed deleted as of 0.9.7b?!? */
     573                 :            :   
     574                 :            :   DD("keygen signing request %s", lk);
     575                 :          2 :   X509_REQ_sign(req, pkey, EVP_md5());
     576                 :            :   
     577                 :            :   /* ----- X509 create self signed certificate ----- */
     578                 :            :   
     579                 :            :   DD("keygen making x509ss %s", lk);
     580                 :          2 :   x509ss = X509_new();
     581                 :          2 :   X509_set_version(x509ss, 2); /* Set version to V3 and serial number to zero */
     582                 :          2 :   zx_rand((char*)&cert_ser, 4);
     583                 :          2 :   ASN1_INTEGER_set(X509_get_serialNumber(x509ss), cert_ser);
     584                 :            :   DD("keygen setting various x509ss fields %s", lk);
     585                 :            :     
     586                 :          2 :   X509_set_issuer_name(x509ss, X509_REQ_get_subject_name(req));
     587                 :            : #if 1
     588                 :          2 :   ASN1_TIME_set(X509_get_notBefore(x509ss),0);
     589                 :          2 :   ASN1_TIME_set(X509_get_notAfter(x509ss), 0x7fffffffL); /* The end of the 32 bit Unix epoch */
     590                 :            : #else
     591                 :            :   X509_gmtime_adj(X509_get_notBefore(x509ss),0);
     592                 :            :   X509_gmtime_adj(X509_get_notAfter(x509ss), 0x7fffffffL); /* The end of the 32 bit Unix epoch */
     593                 :            : #endif
     594                 :          2 :   X509_set_subject_name(x509ss, X509_REQ_get_subject_name(req));
     595                 :            :   
     596                 :            :   DD("keygen setting x509ss pubkey %s", lk);
     597                 :          2 :   tmp_pkey =X509_REQ_get_pubkey(req);
     598                 :          2 :   X509_set_pubkey(x509ss, tmp_pkey);
     599                 :          2 :   EVP_PKEY_free(tmp_pkey);
     600                 :            :   
     601                 :            :   /* Set up V3 context struct and add certificate extensions. Note
     602                 :            :    * that we need to add (full) suite of CA extensions, otherwise
     603                 :            :    * our cert is not valid for signing itself. */
     604                 :            :   
     605                 :          2 :   ext = X509V3_EXT_conf_nid(0, 0, NID_basic_constraints, "CA:TRUE,pathlen:3");
     606                 :          2 :   X509_add_ext(x509ss, ext, -1);
     607                 :            :   
     608                 :          2 :   ext = X509V3_EXT_conf_nid(0, 0, NID_netscape_cert_type, "client,server,email,objsign,sslCA,emailCA,objCA");
     609                 :          2 :   X509_add_ext(x509ss, ext, -1);
     610                 :            :   
     611                 :          2 :   ext = X509V3_EXT_conf_nid(0, 0, NID_key_usage, "digitalSignature,nonRepudiation,keyEncipherment,dataEncipherment,keyAgreement,keyCertSign,cRLSign");
     612                 :          2 :   X509_add_ext(x509ss, ext, -1);
     613                 :            : 
     614                 :          2 :   ext = X509V3_EXT_conf_nid(0, 0, NID_netscape_comment, "Auto-Cert, see zxid.org");
     615                 :          2 :   X509_add_ext(x509ss, ext, -1);
     616                 :            :   
     617                 :            :   DD("keygen signing x509ss %s", lk);
     618         [ -  + ]:          2 :   if (!(X509_sign(x509ss, pkey, EVP_md5()))) {
     619                 :          0 :     ERR("Failed to sign x509ss %s", lk);
     620                 :          0 :     zx_report_openssl_error("X509_sign");
     621                 :          0 :     return 0;
     622                 :            :   }
     623                 :            :   DD("keygen x509ss ready %s", lk);
     624                 :            : 
     625                 :            :   /* ----- Output phase ----- */
     626                 :            : 
     627                 :          2 :   um = umask(0077);  /* Key material should be readable only by owner */
     628                 :            : 
     629                 :          2 :   wbio_csr = BIO_new(BIO_s_mem());
     630                 :            :   DD("write_csr %s", lk);
     631         [ -  + ]:          2 :   if (!PEM_write_bio_X509_REQ(wbio_csr, req)) {
     632                 :          0 :     ERR("write_csr %s", lk);
     633                 :          0 :     zx_report_openssl_error("write_csr");
     634                 :          0 :     return 0;
     635                 :            :   }
     636                 :          2 :   len = BIO_get_mem_data(wbio_csr, &p);
     637                 :            : 
     638                 :          2 :   write_all_path_fmt("auto_cert csr", buflen, buf,
     639                 :            :                      "%s" ZXID_PEM_DIR "csr-%s", cf->path, name,
     640                 :            :                      "%.*s", len, p);
     641                 :          2 :   BIO_free_all(wbio_csr);
     642                 :            : 
     643                 :            :   /* Output combined self signed plus private key file. It is important
     644                 :            :    * that this happens after csr so that buf is left with this data
     645                 :            :    * so that the caller can then parse it. */
     646                 :            : 
     647                 :          2 :   wbio_cert = BIO_new(BIO_s_mem());
     648                 :            :   DD("write_cert %s", lk);
     649         [ -  + ]:          2 :   if (!PEM_write_bio_X509(wbio_cert, x509ss)) {
     650                 :          0 :     ERR("write_cert %s", lk);
     651                 :          0 :     zx_report_openssl_error("write_cert");
     652                 :          0 :     return 0;
     653                 :            :   }
     654                 :          2 :   len = BIO_get_mem_data(wbio_cert, &p);
     655                 :            : 
     656                 :          2 :   wbio_pkey = BIO_new(BIO_s_mem());
     657                 :            :   DD("write_private_key %s", lk);
     658         [ -  + ]:          2 :   if (!PEM_write_bio_PrivateKey(wbio_pkey, pkey, 0,0,0,0,0)) {
     659                 :          0 :     ERR("write_private_key %s", lk);
     660                 :          0 :     zx_report_openssl_error("write_private_key");
     661                 :          0 :     return 0;
     662                 :            :   }
     663                 :          2 :   lenq = BIO_get_mem_data(wbio_pkey, &q);
     664                 :            : 
     665                 :          2 :   write_all_path_fmt("auto_cert ss", buflen, buf,
     666                 :            :                      "%s" ZXID_PEM_DIR "%s", cf->path, name,
     667                 :            :                      "%.*s%.*s", len, p, lenq, q);
     668                 :            : 
     669                 :          2 :   BIO_free_all(wbio_cert);
     670                 :          2 :   BIO_free_all(wbio_pkey);
     671                 :            : 
     672                 :          2 :   umask(um);
     673                 :            : 
     674                 :          2 :   EVP_PKEY_free(pkey);
     675                 :          2 :   X509_REQ_free(req);
     676                 :          2 :   X509_free(x509ss);
     677                 :          2 :   X509V3_EXT_cleanup();
     678                 :          2 :   OBJ_cleanup();
     679                 :            : 
     680                 :          2 :   zxlog(cf, 0, 0, 0, 0, 0, 0, 0, 0, "K", "KEYGEN", name, 0);
     681   [ -  +  #  # ]:          2 :   D("keygen done. %s", lk);
     682                 :          2 :   return 1;
     683                 :            : #else
     684                 :            :   ERR("ZXID was compiled without USE_OPENSSL. This means self signed certificate generation facility is unavailable. Recompile ZXID. %s", lk);
     685                 :            :   return 0;
     686                 :            : #endif
     687                 :            : }
     688                 :            : 
     689                 :            : /*
     690                 :            : 
     691                 :            : A Practical Approach of X.509 Attribute Certificate Framework as Support to Obtain Privilege Delegation
     692                 :            : Jose A. Montenegro and Fernando Moya
     693                 :            : Computer Science Department, E.T.S. Ingenieria Informatica, Universidad de Malage, Spain
     694                 :            : Lecture Notes in Computer Science, 2004, Volume 3093/2004, 624, DOI: 10.1007/978-3-540-25980-0_13 
     695                 :            : 
     696                 :            :  Abstract This work introduces a particular implementation of the
     697                 :            : X.509 Attribute Certificate framework (Xac), presented in the ITU-T
     698                 :            : Recommendation. The implementation is based on the use of the Openssl
     699                 :            : library, that we have chosen for its advantages in comparison with
     700                 :            : other libraries. The paper also describes how the implementation is
     701                 :            : middleware-oriented, focusing on the delegation model specified by
     702                 :            : ITU-T proposal, and taking into consideration the ETSI report about
     703                 :            : Xac.
     704                 :            : 
     705                 :            : RFC3281
     706                 :            : http://tools.ietf.org/html/draft-ietf-pkix-3281update-05
     707                 :            : 
     708                 :            : */
     709                 :            : 
     710                 :            : /*() Create X509 attribute certificate for one attribute and user specified by nameid (pseudonym)
     711                 :            :  *
     712                 :            :  * cf:: zxid configuration object, of which cf->ctx will be used for memory allocation
     713                 :            :  * buflen:: sizeof(buf)
     714                 :            :  * buf:: Buffer used for rendering pem representation of the certificate
     715                 :            :  * log key:: Who and why is calling
     716                 :            :  * nameid:: Name of the subject
     717                 :            :  * name:: Name of the attribute in certificate
     718                 :            :  * val:: Value of the attribute in certificate
     719                 :            :  * returns:: 0 on failure, 1 on success
     720                 :            :  */
     721                 :            : 
     722                 :            : /* Called by:  x509_test, zxid_map_val_ss */
     723                 :            : int zxid_mk_at_cert(zxid_conf* cf, int buflen, char* buf, const char* lk, zxid_nid* nameid, const char* name, struct zx_str* val)
     724                 :        409 : {
     725                 :            : #ifdef USE_OPENSSL
     726                 :            :   BIO*   wbio_cert;
     727                 :            :   int    len;
     728                 :            :   long   cert_ser;
     729                 :            :   char*  p;
     730                 :            :   time_t ts;
     731                 :            :   X509*  x509ss;
     732                 :            :   X509_NAME* issuer;
     733                 :            :   X509_NAME* subject;
     734                 :            :   X509_EXTENSION*  ext;
     735                 :            :   X509*  sign_cert;
     736                 :            :   EVP_PKEY* sign_pkey;
     737                 :            :   char   cn[256];
     738                 :            :   char   ou[256];
     739                 :            : 
     740                 :        409 :   X509V3_add_standard_extensions();
     741                 :            :   
     742   [ +  +  -  + ]:        409 :   D("keygen start lk(%s) name(%s)", lk, name);
     743                 :            : 
     744                 :        409 :   p = strstr(cf->url, "://");
     745         [ +  - ]:        409 :   if (p) {
     746                 :        409 :     p += sizeof("://")-1;
     747                 :        409 :     len = strcspn(p, ":/");
     748         [ -  + ]:        409 :     if (len > sizeof(cn)-2)
     749                 :          0 :       len = sizeof(cn)-2;
     750                 :        409 :     memcpy(cn, p, len);
     751                 :        409 :     cn[len] = 0;
     752                 :            :   } else {
     753                 :          0 :     strcpy(cn, "Unknown server cn. Misconfiguration.");
     754                 :            :   }
     755                 :            :   
     756                 :        409 :   snprintf(ou, sizeof(ou)-1, "SSO Dept ZXID Auto-Cert %s", cf->url);
     757                 :        409 :   ou[sizeof(ou)-1] = 0;  /* must terminate manually as on win32 termination is not guaranteed */
     758                 :            : 
     759                 :        409 :   ts = time(0);
     760                 :        409 :   RAND_seed(&ts,sizeof(ts));
     761                 :            : #ifdef WINDOWS
     762                 :            :   RAND_screen(); /* Loading video display memory into random state */
     763                 :            : #endif
     764                 :            :   
     765                 :            :   //ASN1_INTEGER_set(ri->version, 2L /* version 3 (binary value is one less) */);
     766                 :            :   
     767                 :            :   /* Note on string types and allowable char sets:
     768                 :            :    * V_ASN1_PRINTABLESTRING  [A-Za-z0-9 '()+,-./:=?]   -- Any domain name, but not query string
     769                 :            :    * V_ASN1_IA5STRING        Any 7bit string
     770                 :            :    * V_ASN1_T61STRING        8bit string   */
     771                 :            : 
     772                 :        409 :   issuer = X509_NAME_new();
     773                 :        409 :   subject = X509_NAME_new();  
     774                 :            : 
     775                 :            :   /* Construct DN part by part. We want cn=www.site.com,o=ZXID Auto-Cert */
     776                 :            : 
     777                 :        409 :   zxid_add_name_field(issuer, V_ASN1_PRINTABLESTRING, NID_commonName, cn);
     778                 :        409 :   zxid_add_name_field(issuer, V_ASN1_T61STRING, NID_organizationalUnitName, ou);
     779                 :        409 :   zxid_add_name_field(issuer, V_ASN1_T61STRING, NID_organizationName, cf->org_name);
     780                 :            : 
     781                 :        409 :   zxid_add_name_field(issuer, V_ASN1_T61STRING, NID_localityName, cf->locality);
     782                 :        409 :   zxid_add_name_field(issuer, V_ASN1_T61STRING, NID_stateOrProvinceName, cf->state);
     783                 :        409 :   zxid_add_name_field(issuer, V_ASN1_T61STRING, NID_countryName, cf->country);
     784                 :            : 
     785                 :            :   /* Construct Subject part by part. */
     786                 :            : 
     787         [ +  - ]:        409 :   if (nameid) {
     788   [ +  -  +  -  :        409 :     zxid_add_name_field(subject, V_ASN1_PRINTABLESTRING, NID_commonName,
                   +  - ]
     789                 :            :                         zx_str_to_c(cf->ctx, ZX_GET_CONTENT(nameid)));
     790                 :        409 :     zxid_add_name_field(subject, V_ASN1_T61STRING, NID_organizationalUnitName,
     791                 :            :                         zx_str_to_c(cf->ctx, &nameid->SPNameQualifier->g));  /* SP */
     792                 :        409 :     zxid_add_name_field(subject, V_ASN1_T61STRING, NID_organizationName,
     793                 :            :                         zx_str_to_c(cf->ctx, &nameid->NameQualifier->g));    /* IdP */
     794                 :            :   } else {
     795                 :          0 :     zxid_add_name_field(subject, V_ASN1_PRINTABLESTRING, NID_commonName, "unspecified-see-zxid_mk_at_cert");
     796                 :            :   }
     797                 :            : 
     798                 :            :   /* ----- Create X509 certificate ----- */
     799                 :            :   
     800                 :        409 :   x509ss = X509_new();
     801                 :        409 :   X509_set_version(x509ss, 2); /* Set version to V3 and serial number to zero */
     802                 :        409 :   zx_rand((char*)&cert_ser, 4);
     803                 :        409 :   ASN1_INTEGER_set(X509_get_serialNumber(x509ss), cert_ser);
     804                 :            :   
     805                 :        409 :   X509_set_issuer_name(x509ss, issuer);
     806                 :            : #if 1
     807                 :        409 :   ASN1_TIME_set(X509_get_notBefore(x509ss),0);
     808                 :        409 :   ASN1_TIME_set(X509_get_notAfter(x509ss), 0x7fffffffL); /* The end of the 32 bit Unix epoch */
     809                 :            : #else
     810                 :            :   X509_gmtime_adj(X509_get_notBefore(x509ss),0);
     811                 :            :   X509_gmtime_adj(X509_get_notAfter(x509ss), 0x7fffffffL); /* The end of the 32 bit Unix epoch */
     812                 :            : #endif
     813                 :        409 :   X509_set_subject_name(x509ss, subject);
     814                 :            :   
     815                 :            : #if 0 /* *** schedule to remove */  
     816                 :            :   /* Set up V3 context struct and add certificate extensions. */
     817                 :            :   
     818                 :            :   ext = X509V3_EXT_conf_nid(0, 0, NID_basic_constraints, "CA:TRUE,pathlen:3");
     819                 :            :   X509_add_ext(x509ss, ext, -1);
     820                 :            :   
     821                 :            :   ext = X509V3_EXT_conf_nid(0, 0, NID_netscape_cert_type, "client,server,email,objsign,sslCA,emailCA,objCA");
     822                 :            :   X509_add_ext(x509ss, ext, -1);
     823                 :            :   
     824                 :            :   ext = X509V3_EXT_conf_nid(0, 0, NID_key_usage, "digitalSignature,nonRepudiation,keyEncipherment,dataEncipherment,keyAgreement,keyCertSign,cRLSign");
     825                 :            :   X509_add_ext(x509ss, ext, -1);
     826                 :            : #endif
     827                 :            : 
     828                 :        409 :   ext = X509V3_EXT_conf_nid(0, 0, NID_netscape_comment, "Attribute cert, see zxid.org");
     829                 :        409 :   X509_add_ext(x509ss, ext, -1);
     830                 :            : 
     831                 :            : #if 0
     832                 :            :   X509_ATTRIBUTE*  xa;
     833                 :            :   ASN1_BIT_STRING* bs;
     834                 :            :   ASN1_TYPE* at;
     835                 :            : 
     836                 :            :   /* It seems this gives indigestion to the default CA */
     837                 :            :   DD("keygen populate attributes %s", lk);  /* Add attributes: we really only need cn */
     838                 :            :   
     839                 :            :   xa = X509_ATTRIBUTE_new();
     840                 :            :   xa->value.set = sk_ASN1_TYPE_new_null();
     841                 :            :   /*xa->single = 1; **** this may also be set on some versions */
     842                 :            :   xa->object=OBJ_nid2obj(NID_commonName);
     843                 :            : 
     844                 :            :   bs = ASN1_BIT_STRING_new();
     845                 :            :   bs->type = V_ASN1_PRINTABLESTRING;
     846                 :            :   ASN1_STRING_set(bs, cn, strlen(cn)+1);  /* *** +1 why? Some archaic bug work-around? */
     847                 :            : 
     848                 :            :   at = ASN1_TYPE_new();
     849                 :            :   ASN1_TYPE_set(at, bs->type, (char*)bs);
     850                 :            :   sk_ASN1_TYPE_push(xa->value.set, at);
     851                 :            :   sk_X509_ATTRIBUTE_push(ri->attributes, xa);
     852                 :            :   STACK_OF(X509_ATTRIBUTE) *X509at_add1_attr(STACK_OF(X509_ATTRIBUTE) **x, X509_ATTRIBUTE *attr);
     853                 :            : 
     854                 :            :   /* *** Exactly where on x509ss are the attributes supposed to attach?!? */
     855                 :            : #endif
     856                 :            :   
     857                 :        409 :   zxid_lazy_load_sign_cert_and_pkey(cf, &sign_cert, &sign_pkey, "mk_at_cert");
     858                 :            : 
     859                 :            :   DD("keygen signing x509ss %s", lk);
     860         [ -  + ]:        409 :   if (!(X509_sign(x509ss, sign_pkey, EVP_md5()))) {
     861                 :          0 :     ERR("Failed to sign x509ss %s", lk);
     862                 :          0 :     zx_report_openssl_error("X509_sign");
     863                 :          0 :     return 0;
     864                 :            :   }
     865                 :            :   DD("keygen x509ss ready %s", lk);
     866                 :            : 
     867                 :            :   /* ----- Output phase ----- */
     868                 :            : 
     869                 :        409 :   wbio_cert = BIO_new(BIO_s_mem());
     870                 :            :   DD("write_cert %s", lk);
     871         [ -  + ]:        409 :   if (!PEM_write_bio_X509(wbio_cert, x509ss)) {
     872                 :          0 :     ERR("write_cert %s", lk);
     873                 :          0 :     zx_report_openssl_error("write_cert");
     874                 :          0 :     return 0;
     875                 :            :   }
     876                 :        409 :   len = BIO_get_mem_data(wbio_cert, &p);
     877                 :        409 :   memcpy(buf, p, MIN(len, buflen-1));
     878                 :        409 :   buf[MIN(len, buflen-1)] = 0;
     879                 :            : 
     880                 :            :   //***write_all_path_fmt("auto_cert ss", buflen, buf, "%s" ZXID_PEM_DIR "%s", cf->path, name,  "%.*s", len, p);
     881                 :            : 
     882                 :        409 :   BIO_free_all(wbio_cert);
     883                 :            : 
     884                 :        409 :   X509_free(x509ss);
     885                 :        409 :   X509V3_EXT_cleanup();
     886                 :        409 :   OBJ_cleanup();
     887                 :            : 
     888                 :        409 :   zxlog(cf, 0, 0, 0, 0, 0, 0, 0, 0, "K", "X509ATCERT", name, 0);
     889   [ +  +  -  + ]:        409 :   D("at cert done. %s", lk);
     890                 :        409 :   return 1;
     891                 :            : #else
     892                 :            :   ERR("ZXID was compiled without USE_OPENSSL. This means X509 attribute certificate generation facility is unavailable. Recompile ZXID. %s", lk);
     893                 :            :   return 0;
     894                 :            : #endif
     895                 :            : }
     896                 :            : 
     897                 :            : /* Adapted by Sampo from FreeBSD md5_crypt.c, which is licensed as follows
     898                 :            :  * ----------------------------------------------------------------------------
     899                 :            :  * "THE BEER-WARE LICENSE" (Revision 42):
     900                 :            :  * <phk@login.dknet.dk> wrote this file.  As long as you retain this notice you
     901                 :            :  * can do whatever you want with this stuff. If we meet some day, and you think
     902                 :            :  * this stuff is worth it, you can buy me a beer in return.   Poul-Henning Kamp
     903                 :            :  * ----------------------------------------------------------------------------
     904                 :            :  */
     905                 :            : 
     906                 :            : extern char pw_basis_64[64];
     907                 :            : 
     908                 :            : /* Called by:  zx_md5_crypt x6 */
     909                 :         66 : static void to64(char *s, unsigned long v, int n) {
     910         [ +  + ]:        374 :   while (--n >= 0) {
     911                 :        242 :     *s++ = pw_basis_64[v & 0x3f];
     912                 :        242 :     v >>= 6;
     913                 :            :   }
     914                 :         66 : }
     915                 :            : 
     916                 :            : /*() Compute MD5-Crypt password hash (starts by $1$)
     917                 :            :  * 
     918                 :            :  * pw:: Password in plain
     919                 :            :  * salt:: 0-8 chars of salt. Preceding $1$ is automatically skipped. Salt ends in $ or nul.
     920                 :            :  * buf:: must be at least 120 chars
     921                 :            :  * return:: buf, nul terminated */
     922                 :            : 
     923                 :            : /* Called by:  main x2, zxid_pw_authn */
     924                 :            : char* zx_md5_crypt(const char* pw, const char* salt, char* buf)
     925                 :         11 : {
     926                 :         11 :   const char* magic = "$1$";    /* magic prefix to identify algo */
     927                 :            :   char* p;
     928                 :            :   const char *sp, *ep;
     929                 :            :   unsigned char final[16];
     930                 :            :   int sl, pl, i, j;
     931                 :            :   MD5_CTX ctx, ctx1;
     932                 :            :   unsigned long l;
     933                 :            : 
     934                 :            :   /* Refine the Salt first */
     935                 :         11 :   sp = salt;
     936                 :            :   
     937                 :            :   /* If it starts with the magic string, then skip that */
     938         [ +  - ]:         11 :   if (!strncmp(sp, magic, strlen(magic)))
     939                 :         11 :     sp += strlen(magic);
     940                 :            :   
     941                 :            :   /* It stops at the first '$', max 8 chars */
     942   [ +  -  +  +  :         11 :   for (ep = sp; *ep && *ep != '$' && ep < (sp + 8); ep++) ;
                   +  - ]
     943                 :         11 :   sl = ep - sp;  /* get the length of the true salt */
     944                 :            :   
     945                 :         11 :   MD5_Init(&ctx);
     946                 :         11 :   MD5_Update(&ctx, (unsigned const char *)pw, strlen(pw));       /* pw 1st, as it's most unknown */
     947                 :         11 :   MD5_Update(&ctx, (unsigned const char *)magic, strlen(magic)); /* Then our magic string */
     948                 :         11 :   MD5_Update(&ctx, (unsigned const char *)sp, sl);               /* Then the raw salt */
     949                 :            :   
     950                 :            :   /* Then just as many characters of the MD5(pw,salt,pw) */
     951                 :         11 :   MD5_Init(&ctx1);
     952                 :         11 :   MD5_Update(&ctx1, (unsigned const char *)pw, strlen(pw));
     953                 :         11 :   MD5_Update(&ctx1, (unsigned const char *)sp, sl);
     954                 :         11 :   MD5_Update(&ctx1, (unsigned const char *)pw, strlen(pw));
     955                 :         11 :   MD5_Final(final, &ctx1);
     956         [ +  + ]:         22 :   for (pl = strlen(pw); pl > 0; pl -= 16)
     957                 :         11 :     MD5_Update(&ctx, (unsigned const char *)final, pl>16 ? 16 : pl);
     958                 :            : 
     959                 :         11 :   ZERO(final, sizeof(final)); /* Don't leave anything around in vm they could use. */
     960                 :            :   
     961                 :            :   /* Then something really weird... */
     962         [ +  + ]:         44 :   for (j = 0, i = strlen(pw); i; i >>= 1)
     963         [ +  + ]:         33 :     if (i & 1)
     964                 :         22 :       MD5_Update(&ctx, (unsigned const char *)final+j, 1);
     965                 :            :     else
     966                 :         11 :       MD5_Update(&ctx, (unsigned const char *)pw+j, 1);
     967                 :            :   
     968                 :         11 :   strcpy(buf, magic);   /* Start the output string */
     969                 :         11 :   strncat(buf, sp, sl);
     970                 :         11 :   strcat(buf, "$");
     971                 :            :   
     972                 :         11 :   MD5_Final(final, &ctx);
     973                 :            :   
     974                 :            :   /* and now, just to make sure things don't run too fast
     975                 :            :    * On a 60 Mhz Pentium this takes 34 msec, so you would
     976                 :            :    * need 30 seconds to build a 1000 entry dictionary... */
     977         [ +  + ]:      11011 :   for (i = 0; i < 1000; i++) {
     978                 :      11000 :     MD5_Init(&ctx1);
     979         [ +  + ]:      11000 :     if (i & 1)
     980                 :       5500 :       MD5_Update(&ctx1, (unsigned const char *)pw, strlen(pw));
     981                 :            :     else
     982                 :       5500 :       MD5_Update(&ctx1, (unsigned const char *)final, 16);
     983                 :            :     
     984         [ +  + ]:      11000 :     if (i % 3)
     985                 :       7326 :       MD5_Update(&ctx1, (unsigned const char *)sp, sl);
     986                 :            :     
     987         [ +  + ]:      11000 :     if (i % 7)
     988                 :       9427 :       MD5_Update(&ctx1, (unsigned const char *)pw, strlen(pw));
     989                 :            :     
     990         [ +  + ]:      11000 :     if (i & 1)
     991                 :       5500 :       MD5_Update(&ctx1, (unsigned const char *)final, 16);
     992                 :            :     else
     993                 :       5500 :       MD5_Update(&ctx1, (unsigned const char *)pw, strlen(pw));
     994                 :      11000 :     MD5_Final(final, &ctx1);
     995                 :            :   }
     996                 :            :   
     997                 :         11 :   p = buf + strlen(buf);
     998                 :            : 
     999                 :         11 :   l = (final[0] << 16) | (final[6] << 8) | final[12];  to64(p, l, 4);  p += 4;
    1000                 :         11 :   l = (final[1] << 16) | (final[7] << 8) | final[13];  to64(p, l, 4);  p += 4;
    1001                 :         11 :   l = (final[2] << 16) | (final[8] << 8) | final[14];  to64(p, l, 4);  p += 4;
    1002                 :         11 :   l = (final[3] << 16) | (final[9] << 8) | final[15];  to64(p, l, 4);  p += 4;
    1003                 :         11 :   l = (final[4] << 16) | (final[10] << 8) | final[5];  to64(p, l, 4);  p += 4;
    1004                 :         11 :   l = final[11];                                       to64(p, l, 2);  p += 2;
    1005                 :         11 :   *p = '\0';
    1006                 :            : 
    1007                 :         11 :   ZERO(final, sizeof(final)); /* Don't leave anything around in vm they could use. */
    1008                 :         11 :   return buf;
    1009                 :            : }
    1010                 :            : 
    1011                 :            : /* EOF  -  zxcrypto.c */

Generated by: LCOV version 1.9