LCOV - code coverage report
Current view: top level - zxid - zxsig.c (source / functions) Hit Total Coverage
Test: ZXID Code Coverage Lines: 223 376 59.3 %
Date: 2010-12-19 Functions: 10 10 100.0 %
Branches: 102 261 39.1 %

           Branch data     Line data    Source code
       1                 :            : /* zxsig.c  -  Signature generation and validation
       2                 :            :  * Copyright (c) 2010 Sampo Kellomaki (sampo@iki.fi), All Rights Reserved.
       3                 :            :  * Copyright (c) 2006-2009 Symlabs (symlabs@symlabs.com), All Rights Reserved.
       4                 :            :  * Author: Sampo Kellomaki (sampo@iki.fi)
       5                 :            :  * This is confidential unpublished proprietary source code of the author.
       6                 :            :  * NO WARRANTY, not even implied warranties. Contains trade secrets.
       7                 :            :  * Distribution prohibited unless authorized in writing.
       8                 :            :  * Licensed under Apache License 2.0, see file COPYING.
       9                 :            :  * $Id: zxsig.c,v 1.29 2010-01-08 02:10:09 sampo Exp $
      10                 :            :  *
      11                 :            :  * 29.9.2006, created --Sampo
      12                 :            :  * 23.9.2007, added XML ENC support --Sampo
      13                 :            :  * 8.10.2007, added XML signing support --Sampo
      14                 :            :  * 4.10.2008, improved documentation --Sampo
      15                 :            :  * 1.12.2010, improved logging of canonicalizations --Sampo
      16                 :            :  */
      17                 :            : 
      18                 :            : #include <memory.h>
      19                 :            : #include <string.h>
      20                 :            : 
      21                 :            : #ifdef USE_OPENSSL
      22                 :            : #include <openssl/x509.h>
      23                 :            : #include <openssl/sha.h>
      24                 :            : #include <openssl/md5.h>
      25                 :            : #include <openssl/evp.h>
      26                 :            : #include <openssl/rsa.h>
      27                 :            : #include <openssl/dsa.h>
      28                 :            : #include <openssl/err.h>
      29                 :            : #endif
      30                 :            : 
      31                 :            : #include "errmac.h"
      32                 :            : #include "platform.h"
      33                 :            : #include "zx.h"
      34                 :            : #include "zxid.h"
      35                 :            : #include "zxidutil.h"
      36                 :            : #include "zxidconf.h"
      37                 :            : #include "c/zx-data.h"   /* For the XMLDSIG code. */
      38                 :            : #include "c/zx-const.h"
      39                 :            : 
      40                 :            : ZXID_DECL struct zx_ds_KeyInfo_s* zxid_key_info(zxid_conf* cf, struct zx_elem_s* father, X509* x);
      41                 :            : 
      42                 :            : //static char*
      43                 :            : #define priv_key_missing_msg "Private key missing. Perhaps you have not installed one in the certificate file in the /var/zxid/pem directory (or other directory if configured, see previous error messages for file reading trouble)? Other reasons: permissions do not allow reading the key (current uid=%d gid=%d), the directory permissions do not allow reading, the private key file is empty, wrong format, or corrupt; or the private key is protected with a password (remove password prior to use with zxid). See http://zxid.org/html/zxid-cot.html for further help."
      44                 :            : 
      45                 :            : /*(i) Sign, using XML-DSIG, some XML data in the ~sref~ array. The XML data is canonicalized
      46                 :            :  * and the signature is generated and returned. Typically the caller will then insert the
      47                 :            :  * signature to the original data structure and canonicalize for transport.
      48                 :            :  *
      49                 :            :  * c::        ZX context. Used for memory allocation.
      50                 :            :  * n::        Number of elements in the sref array
      51                 :            :  * sref::     An array of <reference id, xml canon> tuples that are
      52                 :            :  *     to be signed. See zxid_add_header_refs() for preparing sref array.
      53                 :            :  * cert::     Certificate (public key) used for signing
      54                 :            :  * priv_key:: Private key used for signing
      55                 :            :  * return::   Signature as XML data, or 0 if failure.
      56                 :            :  *
      57                 :            :  * *Steps*
      58                 :            :  *
      59                 :            :  * 1. Canon tag(s) to sign (done by caller), pass as sig refs
      60                 :            :  * 2. Sha1 each sig ref
      61                 :            :  * 3. Construct the Signature element
      62                 :            :  * 4. Attach signature to the element (done by caller)
      63                 :            :  *
      64                 :            :  * *Typical XML-DSIG Signature*
      65                 :            :  *
      66                 :            :  *   <ds:Signature xmlns:ds="http://www.w3.org/2000/09/xmldsig#">
      67                 :            :  *     <ds:SignedInfo>
      68                 :            :  *       <ds:CanonicalizationMethod Algorithm="http://www.w3.org/2001/10/xml-exc-c14n#"/>
      69                 :            :  *       <ds:SignatureMethod Algorithm="http://www.w3.org/2000/09/xmldsig#rsa-sha1"/>
      70                 :            :  *       <ds:Reference URI="#CREDm7unLxp2sOXQYfDR8E4F">
      71                 :            :  *         <ds:Transforms>
      72                 :            :  *           <ds:Transform Algorithm="http://www.w3.org/2000/09/xmldsig#enveloped-signature"/>
      73                 :            :  *           <ds:Transform Algorithm="http://www.w3.org/2001/10/xml-exc-c14n#">
      74                 :            :  *             <ec:InclusiveNamespaces
      75                 :            :  *                 xmlns:ec="http://www.w3.org/2001/10/xml-exc-c14n#"
      76                 :            :  *                 PrefixList="xasa"/></></>
      77                 :            :  *         <ds:DigestMethod Algorithm="http://www.w3.org/2000/09/xmldsig#sha1"/>
      78                 :            :  *         <ds:DigestValue>I2wmlQu11nvfSepvzor29kAZwAo=</></></>
      79                 :            :  *     <ds:SignatureValue>
      80                 :            :  *       FK6X9qO8qZntp3CeFbA7gpG9n9rWyJWlzSXy0vKNspwMGdl8HPfOGcXEs2Ts=</></>
      81                 :            :  */
      82                 :            : 
      83                 :            : /* Called by:  zxid_anoint_a7n, zxid_anoint_sso_resp, zxid_az_soap x3, zxid_idp_soap_dispatch x2, zxid_idp_sso, zxid_mk_art_deref, zxid_sp_mni_soap, zxid_sp_slo_soap, zxid_sp_soap_dispatch x7, zxid_ssos_anreq, zxid_wsf_sign */
      84                 :            : struct zx_ds_Signature_s* zxsig_sign(struct zx_ctx* c, int n, struct zxsig_ref* sref, X509* cert, EVP_PKEY* priv_key)
      85                 :       1196 : {
      86                 :            :   char sha1[20];
      87                 :            :   char* sigu;
      88                 :            :   int siglen;
      89                 :            :   RSA* rsa;
      90                 :            :   DSA* dsa;
      91                 :            :   struct zx_str* ss;
      92                 :            :   struct zx_str* b64;
      93                 :            :   struct zx_ds_Reference_s* ref;
      94                 :       1196 :   struct zx_ds_Signature_s* sig = zx_NEW_ds_Signature(c,0);
      95                 :       1196 :   struct zx_ds_SignedInfo_s* si = sig->SignedInfo = zx_NEW_ds_SignedInfo(c, &sig->gg);
      96                 :       1196 :   si->CanonicalizationMethod = zx_NEW_ds_CanonicalizationMethod(c, &si->gg);
      97                 :       1196 :   si->CanonicalizationMethod->Algorithm = zx_ref_attr(c, &si->CanonicalizationMethod->gg, zx_Algorithm_ATTR, CANON_ALGO);
      98                 :       1196 :   si->SignatureMethod = zx_NEW_ds_SignatureMethod(c, &si->gg);
      99                 :       1196 :   si->SignatureMethod->Algorithm = zx_ref_attr(c, &si->SignatureMethod->gg, zx_Algorithm_ATTR, SIG_ALGO);
     100                 :            : 
     101         [ +  + ]:       3495 :   for (; n; --n, ++sref) {
     102                 :       2299 :     ref = zx_NEW_ds_Reference(c, &si->gg);
     103                 :       2299 :     ref->Transforms = zx_NEW_ds_Transforms(c, &ref->gg);
     104                 :       2299 :     ref->Transforms->Transform = zx_NEW_ds_Transform(c, &ref->Transforms->gg);
     105                 :       2299 :     ref->Transforms->Transform->Algorithm = zx_ref_attr(c, &ref->Transforms->Transform->gg, zx_Algorithm_ATTR, CANON_ALGO);
     106                 :            : 
     107                 :       2299 :     ref->Transforms->Transform = zx_NEW_ds_Transform(c, &ref->Transforms->gg);
     108                 :       2299 :     ref->Transforms->Transform->Algorithm = zx_ref_attr(c, &ref->Transforms->Transform->gg, zx_Algorithm_ATTR, ENVELOPED_ALGO);
     109                 :            :     
     110                 :       2299 :     ref->DigestMethod = zx_NEW_ds_DigestMethod(c, &ref->gg);
     111                 :       2299 :     ref->DigestMethod->Algorithm = zx_ref_attr(c, &ref->DigestMethod->gg, zx_Algorithm_ATTR, DIGEST_ALGO);
     112                 :            :     
     113                 :       2299 :     ref->URI = zx_attrf(c, &ref->gg, zx_URI_ATTR, "#%.*s", sref->id->len, sref->id->s);
     114                 :       2299 :     SHA1((unsigned char*)sref->canon->s, sref->canon->len, (unsigned char*)sha1);
     115                 :       2299 :     b64 = zx_new_len_str(c, SIMPLE_BASE64_LEN(sizeof(sha1)));
     116                 :       2299 :     base64_fancy_raw(sha1, sizeof(sha1), b64->s, std_basis_64, 1<<31, 0, 0, '=');
     117                 :       2299 :     ref->DigestValue = zx_new_str_elem(c, &ref->gg, zx_ds_DigestValue_ELEM, b64);
     118                 :       2299 :     si->Reference = ref;  /* *** Need to reverse the list? */
     119                 :            :     /* This debug print allows you to debug canonicalization reated signature
     120                 :            :      * problems from signer's end. The verifier's end is aroind line zxsig.c:270
     121                 :            :      * in zxsig_validate() */
     122                 :            :     DD("SIG REF(#%.*s) SHA1(%.*s) CANON(%.*s)", sref->id->len, sref->id->s, b64->len, b64->s, sref->canon->len, sref->canon->s);
     123   [ +  +  -  + ]:       2299 :     D("SIG REF(#%.*s) SHA1(%.*s)", sref->id->len, sref->id->s, b64->len, b64->s);
     124                 :       2299 :     D_XML_BLOB(0, "SIG CANON", sref->canon->len, sref->canon->s);
     125                 :       2299 :     zx_reverse_elem_lists(&si->Reference->gg);
     126                 :            :   }
     127                 :       1196 :   zx_reverse_elem_lists(&si->gg);
     128                 :            :   
     129                 :       1196 :   c->enc_tail_opt = 0;
     130                 :       1196 :   ss = zx_EASY_ENC_elem(c, &si->gg);
     131                 :       1196 :   SHA1((unsigned char*)ss->s, ss->len, (unsigned char*)sha1);
     132                 :       1196 :   zx_str_free(c, ss);
     133                 :            :   
     134         [ -  + ]:       1196 :   if (!priv_key) {
     135                 :          0 :     ERR(priv_key_missing_msg, geteuid(), getegid());
     136                 :          0 :     return 0;
     137                 :            :   }
     138                 :            : 
     139      [ +  -  - ]:       1196 :   switch (EVP_PKEY_type(priv_key->type)) {
     140                 :            :   case EVP_PKEY_RSA:
     141                 :       1196 :     rsa = EVP_PKEY_get1_RSA(priv_key);
     142                 :       1196 :     siglen = RSA_size(rsa);
     143                 :       1196 :     sigu = ZX_ALLOC(c, siglen);
     144                 :            :     
     145         [ -  + ]:       1196 :     if (!RSA_sign(NID_sha1, (unsigned char*)sha1, sizeof(sha1), (unsigned char*)sigu, (unsigned int*)&siglen, rsa)) {
     146                 :          0 :       ERR("RSA_sign() failed. Bad certificate or private key? %p", rsa);
     147                 :          0 :       zx_report_openssl_error("signing error");
     148                 :          0 :       ZX_FREE(c, sigu);
     149                 :          0 :       return 0;
     150                 :            :     }
     151                 :       1196 :     break;
     152                 :            :   case EVP_PKEY_DSA:
     153                 :          0 :     dsa = EVP_PKEY_get1_DSA(priv_key);
     154                 :          0 :     siglen = DSA_size(dsa);
     155                 :          0 :     sigu = ZX_ALLOC(c, siglen);
     156                 :            :     
     157         [ #  # ]:          0 :     if (!DSA_sign(NID_sha1, (unsigned char*)sha1, sizeof(sha1), (unsigned char*)sigu, (unsigned int*)&siglen, dsa)) {
     158                 :          0 :       ERR("DSA_sign() failed. Bad certificate or private key? %p", dsa);
     159                 :          0 :       zx_report_openssl_error("signing error");
     160                 :          0 :       ZX_FREE(c, sigu);
     161                 :          0 :       return 0;
     162                 :            :     }
     163                 :          0 :     break;
     164                 :            :   default:
     165                 :          0 :     ERR("Unknown private key type 0x%x. Wrong or corrupt private key?", priv_key->type);
     166                 :          0 :     return 0;
     167                 :            :   }
     168                 :            :   
     169                 :       1196 :   b64 = zx_new_len_str(c, SIMPLE_BASE64_LEN(siglen));
     170                 :       1196 :   base64_fancy_raw(sigu, siglen, b64->s, std_basis_64, 1<<31, 0, 0, '=');
     171                 :       1196 :   ZX_FREE(c, sigu);
     172                 :       1196 :   sig->SignatureValue = zx_NEW_ds_SignatureValue(c, &sig->gg);
     173                 :       1196 :   zx_add_content(c, &sig->SignatureValue->gg, b64);
     174                 :       1196 :   zx_reverse_elem_lists(&sig->gg);
     175                 :       1196 :   return sig;
     176                 :            : }
     177                 :            : 
     178                 :            : /*() CRNL->NL canonicalization is specified in xml-c14n */
     179                 :            : 
     180                 :            : /* Called by:  zxsig_validate x2 */
     181                 :            : static void zxsig_canon_crnl_inplace(struct zx_str* ss)
     182                 :        827 : {
     183                 :            :   char* p;
     184                 :            :   char* lim;
     185   [ +  -  +  -  :        827 :   if (!ss || !ss->len || !ss->s) {
                   -  + ]
     186                 :          0 :     ERR("Asked to canonicalize null or empty string %p", ss);
     187                 :          0 :     return;
     188                 :            :   }
     189                 :        827 :   p = ss->s;
     190                 :        827 :   lim = p + ss->len;
     191         [ +  - ]:       1722 :   while (p < lim) {
     192                 :        895 :     p = memchr(p, 0x0d, lim-p);
     193         [ +  + ]:        895 :     if (!p)
     194                 :        827 :       break;
     195                 :         68 :     --lim;
     196   [ -  +  #  # ]:         68 :     D("Canonicalizing CRNL to NL %d", lim-p);
     197                 :         68 :     memmove(p, p+1, lim-p);  /* *** could be more efficient */
     198                 :            :   }
     199                 :        827 :   ss->len = lim - ss->s;
     200                 :            : }
     201                 :            : 
     202                 :            : /*(i) Validate XML-DSIG signature over XML data found in ~sref~ array.
     203                 :            :  * Signature is validated agaist provided certificate, which
     204                 :            :  * must have been previously looked up, usually using Issuer field of message
     205                 :            :  * and metadata of the signing party. Trust in the certificate must have
     206                 :            :  * been established by other means.
     207                 :            :  *
     208                 :            :  * c::      ZX context. Used for memory allocation.
     209                 :            :  * cert::   Signing party's certificate (public key), typically from metadata. If NULL,
     210                 :            :  *          then only the hashes (and hence canonicalization) are checked, but the
     211                 :            :  *          public key crypto part is not performed, and ZXSIG_BAD_CERT is returned.
     212                 :            :  * sig::    Parsed XML-DSIG data structure
     213                 :            :  * n::      Number of elements in the sref array
     214                 :            :  * sref::   An array of <reference sref, xml data structure blob> tuples that are
     215                 :            :  *     referenced by the signature
     216                 :            :  * return:: ZXSIG value. 0 (ZXSIG_OK) means success. Any other value is some sort of failure */
     217                 :            : 
     218                 :            : /* Called by:  main x5, sig_validate x2, wsse_sec_validate, zxid_chk_sig, zxid_sp_sso_finalize, zxid_wsc_valid_re_env, zxid_wsf_validate_a7n, zxid_wsp_validate_env */
     219                 :            : int zxsig_validate(struct zx_ctx* c, X509* cert, struct zx_ds_Signature_s* sig, int n, struct zxsig_ref* sref)
     220                 :        218 : {
     221                 :            :   EVP_PKEY* evp_pkey;
     222                 :            :   struct rsa_st* rsa_pkey;
     223                 :            :   struct dsa_st* dsa_pkey;
     224                 :            :   int siz, verdict, nn;
     225                 :            :   char* old_sig_raw;
     226                 :            :   char* lim;
     227                 :            :   char* p;
     228                 :            :   char* q;
     229                 :            :   char md_calc[20];   /* SHA1 is 160 bits. */
     230                 :            :   char md_given[20];  /* SHA1 is 160 bits. */
     231                 :            :   struct zx_ns_s* ns;
     232                 :            :   struct zx_str* ss;
     233                 :            :   struct zx_str* dv;
     234                 :            :   struct zxsig_ref* ssref;
     235                 :            :   struct zx_ds_Transform_s* xform;
     236                 :            :   struct zx_str* algo;
     237                 :        218 :   c->exclude_sig = sig;
     238                 :            : 
     239                 :            :   /* Figure out inclusive namespaces, if any. */
     240                 :        218 :   c->inc_ns = 0;
     241         [ -  + ]:        218 :   if (c->canon_inopt & ZXID_CANON_INOPT_SHIB215IDP_INCLUSIVENAMESPACES) {
     242                 :          0 :     INFO("Warning: Processing <InclusiveNamespaces> has been disabled (config option CANON_INOPT=1). The canonicalization may not be fully xml-exc-c14n compatible (but it may enable interoperation with an IdP that is not fully compatible). %x", c->canon_inopt);
     243                 :            :   } else {
     244         [ +  + ]:        852 :     for (ssref = sref, nn = n; nn; --nn, ++ssref) {
     245         [ -  + ]:        634 :       if (!ssref->sref->Transforms)
     246                 :          0 :         continue;
     247                 :        634 :       for (xform = ssref->sref->Transforms->Transform;
     248   [ +  +  +  + ]:       2522 :            xform && xform->gg.g.tok == zx_ds_Transform_ELEM;
     249                 :       1254 :            xform = (void*)xform->gg.g.n) {
     250         [ +  + ]:       1254 :         ss = xform->InclusiveNamespaces ? &xform->InclusiveNamespaces->PrefixList->g : 0;
     251   [ +  +  +  - ]:       1254 :         if (!ss || !ss->len)
     252                 :            :           continue;
     253         [ +  + ]:          3 :         for (p = ss->s, lim = p + ss->len; p < lim; ) {
     254                 :          1 :           q = memchr(p, ' ', lim-p);
     255         [ +  - ]:          1 :           if (!q)
     256                 :          1 :             siz = lim-p;
     257                 :            :           else
     258                 :          0 :             siz = q - p;
     259                 :          1 :           ns = zx_prefix_seen(c, siz, p);
     260         [ -  + ]:          1 :           if (!ns) {
     261                 :          0 :             INFO("InclusiveNamespaces/@PrefixList contains unknown ns prefix(%.*s)", siz, p);
     262                 :          0 :             p += siz + 1;
     263                 :          0 :             continue;
     264                 :            :           }
     265                 :          1 :           p += siz + 1;
     266         [ +  - ]:          1 :           if (!zx_in_inc_ns(c, ns)) {
     267                 :          1 :             ns->inc_n = c->inc_ns;
     268                 :          1 :             c->inc_ns = ns;
     269                 :            :           }
     270                 :            :         }
     271                 :            :       }
     272                 :            :     }
     273                 :            :   }
     274                 :        218 :   c->inc_ns_len = c->inc_ns;
     275                 :        218 :   zx_pop_seen(sref->pop_seen);
     276                 :            : 
     277                 :        218 :   algo = &sref->sref->DigestMethod->Algorithm->g;
     278         [ +  + ]:        840 :   for (; n; --n, ++sref) {
     279                 :        626 :     c->enc_tail_opt = 0;
     280                 :        626 :     ss = zx_EASY_ENC_elem(c, sref->blob);
     281                 :        626 :     zxsig_canon_crnl_inplace(ss);
     282         [ +  - ]:        626 :     if (       ZX_STR_ENDS_IN_CONST(algo, "#sha1")) {
     283                 :        626 :       SHA1((unsigned char*)ss->s, ss->len, (unsigned char*)md_calc);
     284                 :        626 :       siz = 20;
     285         [ #  # ]:          0 :     } else if (ZX_STR_ENDS_IN_CONST(algo, "#md5")) {
     286                 :          0 :       MD5((unsigned char*)ss->s, ss->len, (unsigned char*)md_calc);
     287                 :          0 :       siz = 16;
     288                 :            :     } else {
     289                 :          0 :       ERR("Unknown digest algo(%.*s) in sref(%.*s). Only SHA1 and MD5 are supported.",
     290                 :            :           algo->len, algo->s, sref->sref->URI->g.len, sref->sref->URI->g.s);
     291                 :          0 :       ZX_FREE(c, ss);
     292                 :          0 :       return ZXSIG_BAD_DALGO;
     293                 :            :     }
     294   [ +  -  +  -  :        626 :     dv = ZX_GET_CONTENT(sref->sref->DigestValue);
                   +  - ]
     295         [ -  + ]:        626 :     if (dv->len != SIMPLE_BASE64_LEN(siz)) {
     296                 :          0 :       ERR("Message digest(%.*s) length incorrect (%d vs. %d) at sref(%.*s)",
     297                 :            :           dv->len, dv->s, dv->len, SIMPLE_BASE64_LEN(siz),
     298                 :            :           sref->sref->URI->g.len, sref->sref->URI->g.s);
     299                 :          0 :       ZX_FREE(c, ss);
     300                 :          0 :       return ZXSIG_DIGEST_LEN;
     301                 :            :     }
     302                 :        626 :     unbase64_raw(dv->s, dv->s + dv->len, md_given, zx_std_index_64);
     303         [ +  + ]:        626 :     if (memcmp(md_calc, md_given, siz)) {
     304                 :            :       /* See also debug print of original canonicalization for signature
     305                 :            :        * generation around line zxsig.c:115 in zxsig_sign() */
     306                 :            :       DD("Message digest(%.*s) mismatch at sref(%.*s), canon blob(%.*s)", dv->len, dv->s, sref->sref->URI->g.len, sref->sref->URI->g.s, ss->len, ss->s);
     307                 :          4 :       ERR("Message digest(%.*s) mismatch at sref(%.*s)", dv->len, dv->s, sref->sref->URI->g.len, sref->sref->URI->g.s);
     308                 :          4 :       D_XML_BLOB(0, "VFY FAIL CANON BLOB", ss->len, ss->s);
     309                 :          4 :       ZX_FREE(c, ss);
     310                 :          4 :       return ZXSIG_BAD_DIGEST;
     311                 :            :     }
     312                 :        622 :     ZX_FREE(c, ss);
     313                 :            :   }
     314         [ +  + ]:        214 :   if (!cert) {
     315                 :         13 :     ERR("No certificate supplied. Only hashes (and hence canonicalization) verified. %d",0);
     316                 :         13 :     return ZXSIG_BAD_CERT;
     317                 :            :   }
     318                 :        201 :   c->exclude_sig = 0;
     319                 :        201 :   c->enc_tail_opt = 0;
     320                 :        201 :   ss = zx_EASY_ENC_elem(c, &sig->SignedInfo->gg);
     321                 :        201 :   zxsig_canon_crnl_inplace(ss);
     322                 :        201 :   algo = &sig->SignedInfo->SignatureMethod->Algorithm->g;
     323                 :        201 :   evp_pkey = X509_get_pubkey(cert);
     324         [ +  - ]:        201 :   if (!evp_pkey) goto certerr;
     325                 :            : 
     326   [ +  -  +  -  :        201 :   dv = ZX_GET_CONTENT(sig->SignatureValue);
                   +  - ]
     327                 :        201 :   old_sig_raw = ZX_ALLOC(c, SIMPLE_BASE64_PESSIMISTIC_DECODE_LEN(dv->len));
     328                 :        201 :   lim = unbase64_raw(dv->s, dv->s + dv->len, old_sig_raw, zx_std_index_64);
     329         [ +  - ]:        201 :   if (       ZX_STR_ENDS_IN_CONST(algo, "#rsa-sha1")) {
     330                 :            :     /* PKCS#1 v2.0 */
     331                 :        201 :     rsa_pkey = EVP_PKEY_get1_RSA(evp_pkey);
     332         [ +  - ]:        201 :     if (!rsa_pkey) goto certerr;
     333                 :        201 :     SHA1((unsigned char*)ss->s, ss->len, (unsigned char*)md_calc);
     334                 :            :     DD("VFY rsa-sha1 (PKCS#1 v2.0) canon sigInfo(%.*s) %d", ss->len, ss->s, hexdmp("inner sha1: ", md_calc,20,20));
     335                 :        201 :     verdict = RSA_verify(NID_sha1, (unsigned char*)md_calc, 20, (unsigned char*)old_sig_raw, lim - old_sig_raw, rsa_pkey);
     336         [ +  - ]:        201 :     if (!verdict) goto vfyerr;
     337         [ #  # ]:          0 :   } else if (ZX_STR_ENDS_IN_CONST(algo, "#dsa-sha1")) {
     338                 :          0 :     dsa_pkey = EVP_PKEY_get1_DSA(evp_pkey);
     339         [ #  # ]:          0 :     if (!dsa_pkey) goto certerr;
     340                 :          0 :     SHA1((unsigned char*)ss->s, ss->len, (unsigned char*)md_calc);
     341                 :            :     DD("VFY dsa-sha1 canon sigInfo(%.*s) %d", ss->len, ss->s,hexdmp("inner sha1: ",md_calc,20,20));
     342                 :          0 :     verdict = DSA_verify(NID_sha1, (unsigned char*)md_calc, 20, (unsigned char*)old_sig_raw, lim - old_sig_raw, dsa_pkey);
     343         [ #  # ]:          0 :     if (!verdict) goto vfyerr;
     344         [ #  # ]:          0 :   } else if (ZX_STR_ENDS_IN_CONST(algo, "#rsa-md5")) {
     345                 :          0 :     rsa_pkey = EVP_PKEY_get1_RSA(evp_pkey);
     346         [ #  # ]:          0 :     if (!rsa_pkey) goto certerr;
     347                 :          0 :     MD5((unsigned char*)ss->s, ss->len, (unsigned char*)md_calc);
     348                 :            :     DD("VFY rsa-md5 canon sigInfo(%.*s) %d", ss->len, ss->s, hexdmp("inner md5: ",md_calc,16,16));
     349                 :          0 :     verdict = RSA_verify(NID_md5, (unsigned char*)md_calc, 16, (unsigned char*)old_sig_raw, lim - old_sig_raw, rsa_pkey);
     350         [ #  # ]:          0 :     if (!verdict) goto vfyerr;
     351         [ #  # ]:          0 :   } else if (ZX_STR_ENDS_IN_CONST(algo, "#dsa-md5")) {
     352                 :          0 :     dsa_pkey = EVP_PKEY_get1_DSA(evp_pkey);
     353         [ #  # ]:          0 :     if (!dsa_pkey) goto certerr;
     354                 :          0 :     MD5((unsigned char*)ss->s, ss->len, (unsigned char*)md_calc);
     355                 :            :     DD("VFY dsa-md5 canon sigInfo(%.*s) %d", ss->len, ss->s, hexdmp("inner md5: ",md_calc,16,16));
     356                 :          0 :     verdict = DSA_verify(NID_md5, (unsigned char*)md_calc, 16, (unsigned char*)old_sig_raw, lim - old_sig_raw, dsa_pkey);
     357         [ #  # ]:          0 :     if (!verdict) goto vfyerr;
     358                 :            :   } else {
     359                 :          0 :     ERR("Unknown digest algo(%.*s) in sref(%.*s). Only SHA1 and MD5 are supported.",
     360                 :            :         sref->sref->DigestMethod->Algorithm->g.len, sref->sref->DigestMethod->Algorithm->g.s,
     361                 :            :         sref->sref->URI->g.len, sref->sref->URI->g.s);
     362                 :          0 :     ZX_FREE(c, ss);
     363                 :          0 :     return ZXSIG_BAD_SALGO;
     364                 :            :   }  
     365                 :        201 :   ZX_FREE(c, ss);
     366                 :        201 :   return ZXSIG_OK;
     367                 :            : 
     368                 :          0 : certerr:
     369   [ #  #  #  #  :          0 :   ERR("Certificate error. Maybe the certificate does not have any public key type=0x%x matching the algorithm(%.*s)? Or corrupt or wrong cert?", evp_pkey?evp_pkey->type:-1, algo?algo->len:0, algo?algo->s:"");
                   #  # ]
     370                 :          0 :   zx_report_openssl_error("certificate error");
     371                 :          0 :   ZX_FREE(c, ss);
     372                 :          0 :   return ZXSIG_BAD_CERT;
     373                 :            : 
     374                 :          0 : vfyerr:
     375                 :          0 :   zx_report_openssl_error("verification error");
     376                 :            :   DD("VFY FAIL canon sigInfo(%.*s) %d", ss->len, ss->s,hexdmp("inner md_calc: ", md_calc, 20, 20));
     377                 :          0 :   ERR("VFY FAIL canon sigInfo md %d", hexdmp("inner md_calc: ", md_calc, 20, 20));
     378                 :          0 :   D_XML_BLOB(0, "VFY FAIL CANON SIGINFO", ss->len, ss->s);
     379                 :          0 :   ZX_FREE(c, ss);
     380                 :          0 :   return ZXSIG_VFY_FAIL;
     381                 :            : }
     382                 :            : 
     383                 :            : /*() Walk through the OpenSSL error stack and dump it to the stderr.
     384                 :            :  *
     385                 :            :  * logkey:: Way for caller to indicate what the OpenSSL errors are all about
     386                 :            :  * return:: Number of open SSL errors processed, or 0 if none. Often ignored. */
     387                 :            : 
     388                 :            : /* Called by:  main, zx_EVP_CIPHER_key_length, zx_get_rsa_pub_from_cert x2, zx_raw_cipher, zx_rsa_priv_dec, zx_rsa_priv_enc, zx_rsa_pub_dec, zx_rsa_pub_enc, zxid_mk_at_cert x2, zxid_mk_self_sig_cert x4, zxlog_write_line, zxsig_data x2, zxsig_sign x2, zxsig_validate x2, zxsig_verify_data x5 */
     389                 :            : int zx_report_openssl_error(const char* logkey)
     390                 :          2 : {
     391                 :            :   char buf[256];
     392                 :            :   unsigned long err;
     393                 :            :   const char* file;
     394                 :            :   const char* data;
     395                 :          2 :   int flags, line, n_err = 0;
     396                 :          2 :   buf[0] = 0;
     397         [ -  + ]:          4 :   while ((err = ERR_get_error_line_data((const char**)&file, &line, (const char**)&data, &flags))) {
     398                 :          0 :     ERR_error_string_n(err, buf, sizeof(buf));
     399                 :          0 :     buf[sizeof(buf)-1] = 0;
     400   [ #  #  #  #  :          0 :     ERR("%s: OpenSSL error(%lu) %s (%s:%d): %s %x", logkey, err,
                   #  # ]
     401                 :            :         buf, STRNULLCHK(file), line,
     402                 :            :         (data && (flags & ERR_TXT_STRING)) ? data : "?", flags);
     403                 :            :   }
     404                 :          2 :   return n_err;
     405                 :            : }
     406                 :            : 
     407                 :            : /* --------------- Raw data signing and verification. These are building blocks. -------------- */
     408                 :            : 
     409                 :            : /*() Sign a blob of data using rsa-sha1 or dsa-sha1 algorithm.
     410                 :            :  *
     411                 :            :  * c::        ZX context. Used for memory allocation.
     412                 :            :  * len::      Length of the raw data
     413                 :            :  * data::     Raw data to sign
     414                 :            :  * sig::      Result parameter. Raw binary signature data will be returned via this parameter.
     415                 :            :  * priv_key:: Private key used for signing.
     416                 :            :  * lk::       Log key. Used to make logs and error messages more meaningful.
     417                 :            :  * return::   -1 on failure. Upon success the length of the raw signature data. */
     418                 :            : 
     419                 :            : /* Called by:  zxid_saml2_post_enc, zxid_saml2_redir_enc, zxlog_write_line x2 */
     420                 :            : int zxsig_data(struct zx_ctx* c, int len, const char* data, char** sig, EVP_PKEY* priv_key, const char* lk)
     421                 :         13 : {
     422                 :            :   RSA* rsa;
     423                 :            :   DSA* dsa;
     424                 :            :   char sha1[20];  /* 160 bits */
     425                 :         13 :   SHA1((unsigned char*)data, len, (unsigned char*)sha1);
     426                 :            :   
     427                 :            :   DD("%s: data(%.*s)", lk, len, data);
     428                 :            :   DD("%s: data above %d", lk, hexdump("data: ", data, data+len, 4096));
     429                 :            :   DD("%s: sha1 above %d", lk, hexdump("sha1: ", sha1, sha1+20, 20));
     430                 :            : 
     431         [ -  + ]:         13 :   if (!priv_key) {
     432                 :          0 :     ERR(priv_key_missing_msg, geteuid(), getegid());
     433                 :          0 :     return 0;
     434                 :            :   }
     435                 :            : 
     436      [ +  -  - ]:         13 :   switch (EVP_PKEY_type(priv_key->type)) {
     437                 :            :   case EVP_PKEY_RSA:
     438                 :         13 :     rsa = EVP_PKEY_get1_RSA(priv_key);
     439                 :         13 :     len = RSA_size(rsa);
     440                 :         13 :     *sig = ZX_ALLOC(c, len);
     441         [ +  - ]:         13 :     if (RSA_sign(NID_sha1, (unsigned char*)sha1, 20, (unsigned char*)*sig, (unsigned int*)&len, rsa))  /* PKCS#1 v2.0 */
     442                 :         13 :       return len;
     443                 :          0 :     ERR("%s: signing data failed. Perhaps you have bad, or no, RSA private key(%p) len=%d data=%p", lk, rsa, len, data);
     444                 :          0 :     zx_report_openssl_error(lk);
     445                 :          0 :     return -1;
     446                 :            :   case EVP_PKEY_DSA:
     447                 :          0 :     dsa = EVP_PKEY_get1_DSA(priv_key);
     448                 :          0 :     len = DSA_size(dsa);
     449                 :          0 :     *sig = ZX_ALLOC(c, len);
     450         [ #  # ]:          0 :     if (DSA_sign(NID_sha1, (unsigned char*)sha1, 20, (unsigned char*)*sig, (unsigned int*)&len, dsa))  /* PKCS#1 v2.0 */
     451                 :          0 :       return len;
     452                 :          0 :     ERR("%s: signing data failed. Perhaps you have bad, or no, DSA private key(%p) len=%d data=%p", lk, dsa, len, data);
     453                 :          0 :     zx_report_openssl_error(lk);
     454                 :          0 :     return -1;
     455                 :            :   default:
     456                 :          0 :     ERR("%s: Unknown private key type 0x%x. Wrong or corrupt private key?", lk, priv_key->type);
     457                 :          0 :     return -1;
     458                 :            :   }
     459                 :            : }
     460                 :            : 
     461                 :            : /*() Verify a signature over a blob of data using rsa-sha1 algorithm.
     462                 :            :  *
     463                 :            :  * len::      Length of the raw data
     464                 :            :  * data::     Raw data to sign
     465                 :            :  * siglen::   Length of the raw binary signature data
     466                 :            :  * sig::      Raw binary signature data
     467                 :            :  * cert::     Certificate used for signing
     468                 :            :  * lk::       Log key. Used to make logs and error messages more meaningful
     469                 :            :  * return::   ZX_SIG value. o (ZXSIG_OK) means success. Other values mean failure of some sort. */
     470                 :            : 
     471                 :            : /* Called by:  main, zxid_decode_redir_or_post, zxlog_zsig_verify_print */
     472                 :            : int zxsig_verify_data(int len, char* data, int siglen, char* sig, X509* cert, char* lk)
     473                 :          9 : {
     474                 :            :   int verdict;
     475                 :            :   EVP_PKEY* evp_pkey;
     476                 :            :   struct rsa_st* rsa_pkey;
     477                 :            :   struct dsa_st* dsa_pkey;
     478                 :            :   char sha1[20];  /* 160 bits */
     479                 :          9 :   SHA1((unsigned char*)data, len, (unsigned char*)sha1);
     480                 :            :   
     481                 :            :   DD("%s: vfy data above %d", lk, hexdump("data: ", data, data+len, 4096));
     482                 :            :   DD("%s: vfy sig above %d",  lk, hexdump("sig: ",  sig,  sig+siglen, 4096));
     483                 :            :   DD("%s: vfy sha1 above %d", lk, hexdump("sha1: ", sha1, sha1+20, 20));
     484                 :            :   
     485                 :          9 :   evp_pkey = X509_get_pubkey(cert);
     486         [ -  + ]:          9 :   if (!evp_pkey) {
     487                 :          0 :     ERR("%s: Verify failed to get public key from certificate (perhaps you have not supplied any certificate, or it is corrupt or of wrong type) %p", lk, cert);
     488                 :          0 :     zx_report_openssl_error("zxsig rsa vfy get_pub");
     489                 :          0 :     return ZXSIG_BAD_CERT;
     490                 :            :   }
     491      [ +  -  - ]:          9 :   switch (EVP_PKEY_type(evp_pkey->type)) {
     492                 :            :   case EVP_PKEY_RSA:
     493                 :          9 :     rsa_pkey = EVP_PKEY_get1_RSA(evp_pkey);
     494         [ -  + ]:          9 :     if (!rsa_pkey) {
     495                 :          0 :       ERR("RSA vfy: failed to extract RSA get public key from certificate (perhaps you have not supplied any certificate, or it is corrupt or of wrong type) %p", cert);
     496                 :          0 :       zx_report_openssl_error("zxsig rsa vfy rsa get_pub rsa");
     497                 :          0 :       return ZXSIG_BAD_CERT;
     498                 :            :     }
     499                 :            :   
     500                 :          9 :     verdict = RSA_verify(NID_sha1, (unsigned char*)sha1, 20, (unsigned char*)sig, siglen, rsa_pkey);  /* PKCS#1 v2.0 */
     501         [ -  + ]:          9 :     if (!verdict) {
     502                 :          0 :       ERR("RSA signature verify in %s data failed. Perhaps you have bad or no certificate(%p) len=%d data=%p siglen=%d sig=%p", lk, cert, len, data, siglen, sig);
     503                 :          0 :       zx_report_openssl_error(lk);
     504   [ #  #  #  # ]:          0 :       D("RSA_vfy(%s) sig above %d",  lk, hexdump("sig: ",  sig,  sig+siglen, 4096));
     505                 :          0 :       return ZXSIG_VFY_FAIL;
     506                 :            :     } else {
     507   [ +  -  -  + ]:          9 :       D("RSA verify OK %d", verdict);
     508                 :          9 :       return 0;
     509                 :            :     }
     510                 :            :   case EVP_PKEY_DSA:
     511                 :          0 :     dsa_pkey = EVP_PKEY_get1_DSA(evp_pkey);
     512         [ #  # ]:          0 :     if (!dsa_pkey) {
     513                 :          0 :       ERR("DSA vfy: failed to extract DSA get public key from certificate (perhaps you have not supplied any certificate, or it is corrupt or of wrong type) %p", cert);
     514                 :          0 :       zx_report_openssl_error("zxsig dsa vfy dsa get_pub dsa");
     515                 :          0 :       return ZXSIG_BAD_CERT;
     516                 :            :     }
     517                 :            :   
     518                 :          0 :     verdict = DSA_verify(NID_sha1, (unsigned char*)sha1, 20, (unsigned char*)sig, siglen, dsa_pkey);  /* PKCS#1 v2.0 */
     519         [ #  # ]:          0 :     if (!verdict) {
     520                 :          0 :       ERR("DSA signature verify in %s data failed. Perhaps you have bad or no certificate(%p) len=%d data=%p siglen=%d sig=%p", lk, cert, len, data, siglen, sig);
     521                 :          0 :       zx_report_openssl_error(lk);
     522   [ #  #  #  # ]:          0 :       D("DSA_vfy(%s) sig above %d",  lk, hexdump("sig: ",  sig,  sig+siglen, 4096));
     523                 :          0 :       return ZXSIG_VFY_FAIL;
     524                 :            :     } else {
     525   [ #  #  #  # ]:          0 :       D("DSA verify OK %d", verdict);
     526                 :          0 :       return 0;
     527                 :            :     }
     528                 :            :   default:
     529                 :          0 :     ERR("%s: Unknown public key type 0x%x. Wrong or corrupt certificate key?", lk, evp_pkey->type);
     530                 :          0 :     return -1;
     531                 :            :   }    
     532                 :            : }
     533                 :            : 
     534                 :            : /* ------------- XML-ENC support -------------- */
     535                 :            : 
     536                 :            : /*() Symmetric key decryption using XML-ENC. The encryption algorithm is
     537                 :            :  * auto-detected from the XML-ENC data.
     538                 :            :  *
     539                 :            :  * cf:: ZXID configuration object, used for memory allocation
     540                 :            :  * ed:: Encrypted data as XML data structure
     541                 :            :  * symkey:: Symmetric key used for decryption
     542                 :            :  * return:: Decrypted data as zx_str. Caller should free this memory. */
     543                 :            : 
     544                 :            : /* Called by:  zxenc_privkey_dec */
     545                 :            : struct zx_str* zxenc_symkey_dec(zxid_conf* cf, struct zx_xenc_EncryptedData_s* ed, struct zx_str* symkey)
     546                 :        103 : {
     547                 :            :   struct zx_str raw;
     548                 :            :   struct zx_str* ss;
     549                 :            :   char* lim;
     550                 :            :   
     551   [ +  -  +  -  :        103 :   if (!ed || !ed->CipherData || !(ss = ZX_GET_CONTENT(ed->CipherData->CipherValue))) {
          +  -  +  -  +  
                -  -  + ]
     552                 :          0 :     ERR("EncryptedData element not found or malformed %p", ed->CipherData);
     553                 :          0 :     zxlog(cf, 0, 0, 0, 0, 0, 0, 0, "N", "C", "EMISS", 0, "no EncryptedData");
     554                 :          0 :     return 0;
     555                 :            :   }
     556                 :            :   
     557         [ -  + ]:        103 :   if (!symkey) {
     558                 :          0 :     ERR("Symmetric key missing. Perhaps public key operation to recover symmetric key failed (e.g. missing private key, or private key does not match public key). Perhaps the programmer simply failed to pass correct arguments to this function. %d", 0);
     559                 :          0 :     zxlog(cf, 0, 0, 0, 0, 0, 0, 0, "N", "C", "EMISS", 0, "no symkey");
     560                 :          0 :     return 0;
     561                 :            :   }
     562                 :            :   
     563                 :        103 :   raw.s = ZX_ALLOC(cf->ctx, SIMPLE_BASE64_PESSIMISTIC_DECODE_LEN(ss->len));
     564                 :        103 :   lim = unbase64_raw(ss->s, ss->s+ss->len, raw.s, zx_std_index_64);
     565                 :        103 :   raw.len = lim - raw.s;
     566                 :            :   
     567                 :        103 :   ss = &ed->EncryptionMethod->Algorithm->g;
     568   [ -  +  #  # ]:        103 :   if (sizeof(ENC_ALGO_TRIPLEDES_CBC)-1 == ss->len
     569                 :            :       && !memcmp(ENC_ALGO_TRIPLEDES_CBC, ss->s, sizeof(ENC_ALGO_TRIPLEDES_CBC)-1)) {
     570         [ #  # ]:          0 :     if (symkey->len != (192 >> 3)) goto wrong_key_len;
     571                 :          0 :     ss = zx_raw_cipher(cf->ctx, "DES-EDE3-CBC", 0, symkey, raw.len-8, raw.s+8, 8, raw.s);
     572                 :            : 
     573   [ +  -  +  - ]:        206 :   } else if (sizeof(ENC_ALGO_AES128_CBC)-1 == ss->len
     574                 :            :              && !memcmp(ENC_ALGO_AES128_CBC, ss->s, sizeof(ENC_ALGO_AES128_CBC)-1)) {
     575         [ +  - ]:        103 :     if (symkey->len != (128 >> 3)) goto wrong_key_len;
     576                 :        103 :     ss = zx_raw_cipher(cf->ctx, "AES-128-CBC", 0, symkey, raw.len-16, raw.s+16, 16, raw.s);
     577                 :            : 
     578   [ #  #  #  # ]:          0 :   } else if (sizeof(ENC_ALGO_AES192_CBC)-1 == ss->len
     579                 :            :              && !memcmp(ENC_ALGO_AES192_CBC, ss->s, sizeof(ENC_ALGO_AES192_CBC)-1)) {
     580         [ #  # ]:          0 :     if (symkey->len != (192 >> 3)) goto wrong_key_len;
     581                 :          0 :     ss = zx_raw_cipher(cf->ctx, "AES-192-CBC", 0, symkey, raw.len-16, raw.s+16, 16, raw.s);    
     582                 :            : 
     583   [ #  #  #  # ]:          0 :   } else if (sizeof(ENC_ALGO_AES256_CBC)-1 == ss->len
     584                 :            :              && !memcmp(ENC_ALGO_AES256_CBC, ss->s, sizeof(ENC_ALGO_AES256_CBC)-1)) {
     585         [ #  # ]:          0 :     if (symkey->len != (256 >> 3)) goto wrong_key_len;
     586                 :          0 :     ss = zx_raw_cipher(cf->ctx, "AES-256-CBC", 0, symkey, raw.len-16, raw.s+16, 16, raw.s);
     587                 :            :   } else {
     588                 :          0 :     ERR("Unsupported key transformation method(%.*s)", ss->len, ss->s);
     589                 :          0 :     zxlog(cf, 0, 0, 0, 0, 0, 0, 0, "N", "C", "ECRYPT", 0, "unsupported key transformation method");
     590                 :          0 :     return 0;
     591                 :            :   }
     592                 :        103 :   ZX_FREE(cf->ctx, raw.s);
     593                 :            :   DD("plain(%.*s)", ss->len, ss->s);
     594                 :        103 :   D_XML_BLOB(cf, "PLAIN", ss->len, ss->s);
     595                 :        103 :   return ss;
     596                 :            : 
     597                 :          0 :  wrong_key_len:
     598                 :          0 :   ZX_FREE(cf->ctx, raw.s);
     599                 :          0 :   ERR("Wrong key length %d for algo(%.*s)", symkey->len, ss->len, ss->s);
     600                 :          0 :   zxlog(cf, 0, 0, 0, 0, 0, 0, 0, "N", "C", "ECRYPT", 0, "wrong key length");
     601                 :          0 :   return 0;
     602                 :            : }
     603                 :            : 
     604                 :            : /*() Private key decryption using XML-ENC. The encryption algorithm is
     605                 :            :  * auto-detected from the XML-ENC data. The private key is looked up
     606                 :            :  * from the configuration object.
     607                 :            :  *
     608                 :            :  * cf:: ZXID configuration object, used for memory allocation
     609                 :            :  * ed:: Encrypted data as XML data structure
     610                 :            :  * ek:: Symmetric encryption key data structure. If not supplied, the EncryptedKey
     611                 :            :  *     element from EncryptedData is used
     612                 :            :  * return:: Decrypted data as zx_str. Caller should free this memory. */
     613                 :            : 
     614                 :            : /* Called by:  zxid_dec_a7n, zxid_decrypt_nameid, zxid_decrypt_newnym, zxid_get_ses_sso_a7n */
     615                 :            : struct zx_str* zxenc_privkey_dec(zxid_conf* cf, struct zx_xenc_EncryptedData_s* ed, struct zx_xenc_EncryptedKey_s* ek)
     616                 :        103 : {
     617                 :            :   EVP_PKEY* enc_pkey;
     618                 :            :   RSA* rsa;
     619                 :            :   struct zx_str raw;
     620                 :            :   struct zx_str* symkey;
     621                 :            :   struct zx_str* ss;
     622                 :            :   char* lim;
     623                 :            : 
     624         [ -  + ]:        103 :   if (!ed) {
     625                 :          0 :     ERR("Missing or malformed EncryptedData %d", 0);
     626                 :          0 :     return 0;
     627                 :            :   }
     628                 :            : 
     629   [ +  +  +  - ]:        103 :   if (!ek && ed->KeyInfo)
     630                 :         99 :     ek = ed->KeyInfo->EncryptedKey;  /* Nested EncryptionKey method (Shib 2010) */
     631   [ +  -  +  -  :        103 :   if (!ek || !ek->CipherData || !(ss = ZX_GET_CONTENT(ek->CipherData->CipherValue)) || !ss->len) {
          +  -  +  -  +  
             -  +  -  -  
                      + ]
     632                 :          0 :     ERR("EncryptedKey element not found or malformed %p", ek->CipherData);
     633                 :          0 :     zxlog(cf, 0, 0, 0, 0, 0, 0, 0, "N", "C", "EMISS", 0, "EncryptedKey not found");
     634                 :          0 :     return 0;
     635                 :            :   }
     636                 :            :   
     637                 :        103 :   raw.s = ZX_ALLOC(cf->ctx, SIMPLE_BASE64_PESSIMISTIC_DECODE_LEN(ss->len));
     638                 :        103 :   lim = unbase64_raw(ss->s, ss->s+ss->len, raw.s, zx_std_index_64);
     639                 :        103 :   raw.len = lim - raw.s;
     640                 :            :   
     641   [ -  +  #  # ]:        103 :   LOCK(cf->mx, "zxenc_privkey_dec");      
     642         [ +  + ]:        103 :   if (!(enc_pkey = cf->enc_pkey))
     643                 :         39 :     enc_pkey = cf->enc_pkey = zxid_read_private_key(cf, "enc-nopw-cert.pem");
     644   [ -  +  #  # ]:        103 :   UNLOCK(cf->mx, "zxenc_privkey_dec");      
     645         [ -  + ]:        103 :   if (!enc_pkey)
     646                 :          0 :     return 0;
     647                 :            :   
     648   [ +  -  +  -  :        103 :   if (!ek->EncryptionMethod || !(ss = &ek->EncryptionMethod->Algorithm->g) || !ss->len) {
                   -  + ]
     649                 :          0 :     ERR("Missing or malformed EncryptionMethod %p", ek->EncryptionMethod);
     650                 :          0 :     return 0;
     651                 :            :   }
     652                 :            :   
     653   [ +  -  +  - ]:        206 :   if (sizeof(ENC_KEYTRAN_RSA_1_5)-1 == ss->len
     654                 :            :       && !memcmp(ENC_KEYTRAN_RSA_1_5, ss->s, sizeof(ENC_KEYTRAN_RSA_1_5)-1)) {
     655                 :        103 :     rsa = EVP_PKEY_get1_RSA(enc_pkey);
     656                 :        103 :     symkey = zx_rsa_priv_dec(cf->ctx, &raw, rsa, RSA_PKCS1_PADDING);
     657   [ #  #  #  # ]:          0 :   } else if (sizeof(ENC_KEYTRAN_RSA_OAEP)-1 == ss->len
     658                 :            :              && !memcmp(ENC_KEYTRAN_RSA_OAEP, ss->s, sizeof(ENC_KEYTRAN_RSA_OAEP)-1)) {
     659                 :          0 :     rsa = EVP_PKEY_get1_RSA(enc_pkey);
     660                 :          0 :     symkey = zx_rsa_priv_dec(cf->ctx, &raw, rsa, RSA_PKCS1_OAEP_PADDING);
     661                 :            :   } else {
     662                 :          0 :     ERR("Unsupported key transformation method(%.*s)", ss->len, ss->s);
     663                 :          0 :     zxlog(cf, 0, 0, 0, 0, 0, 0, 0, "N", "C", "ECRYPT", 0, "unsupported key transformation method");
     664                 :          0 :     return 0;
     665                 :            :   }
     666                 :        103 :   ZX_FREE(cf->ctx, raw.s);
     667         [ +  - ]:        103 :   if (symkey) {
     668                 :        103 :     ss = zxenc_symkey_dec(cf, ed, symkey);
     669                 :        103 :     zx_str_free(cf->ctx, symkey);
     670                 :        103 :     return ss;
     671                 :            :   } else
     672                 :          0 :     return 0;
     673                 :            : }
     674                 :            : 
     675                 :            : /*() Symmetric key encryption using XML-ENC. The encryption algorith is
     676                 :            :  * auto-detected from the XML-ENC data.
     677                 :            :  *
     678                 :            :  * cf:: ZXID configuration object, used for memory allocation
     679                 :            :  * data:: Data blob to encrypt. Typically serialized XML
     680                 :            :  * ed_id:: The value of the ~Id~ XML attribute of the <EncryptedData> element
     681                 :            :  * symkey:: Raw symmetric key used for encryption
     682                 :            :  * symkey_id:: The value of the ~Id~ XML attribute of the <EncryptedKey> element
     683                 :            :  * return:: Encrypted data as XML data structure. Caller should free this memory.
     684                 :            :  *
     685                 :            :  * *Example of XML-ENC encrypted data using RetrievalMethod pointing to EncryptedID Id="EK38"*
     686                 :            :  *
     687                 :            :  *   <sa:EncryptedID>
     688                 :            :  *     <e:EncryptedData
     689                 :            :  *         xmlns:e="http://www.w3.org/2001/04/xmlenc#"
     690                 :            :  *         Id="ED38"
     691                 :            :  *         Type="http://www.w3.org/2001/04/xmlenc#Element">
     692                 :            :  *       <e:EncryptionMethod Algorithm="http://www.w3.org/2001/04/xmlenc#aes128-cbc"/>
     693                 :            :  *       <ds:KeyInfo xmlns:ds="http://www.w3.org/2000/09/xmldsig#">
     694                 :            :  *         <ds:RetrievalMethod
     695                 :            :  *             Type="http://www.w3.org/2001/04/xmlenc#EncryptedKey"
     696                 :            :  *             URI="#EK38"/></>                                            # N.B. hash
     697                 :            :  *       <e:CipherData>
     698                 :            :  *         <e:CipherValue>FWfOV7aytBE2xIMe...YTA3ImLf9JCM/vdLIMizMf1</></></>
     699                 :            :  *
     700                 :            :  *     <e:EncryptedKey xmlns:e="http://www.w3.org/2001/04/xmlenc#" Id="EK38">
     701                 :            :  *       <e:EncryptionMethod Algorithm="http://www.w3.org/2001/04/xmlenc#rsa-1_5"/>
     702                 :            :  *       <ds:KeyInfo xmlns:ds="http://www.w3.org/2000/09/xmldsig#">
     703                 :            :  *         <ds:X509Data>
     704                 :            :  *           <ds:X509Certificate>***</></></>
     705                 :            :  *       <e:CipherData>
     706                 :            :  *         <e:CipherValue>xf5HkmQM68t...7zRbxkqtniIVnxBHjkA=</></>
     707                 :            :  *       <e:ReferenceList>
     708                 :            :  *         <e:DataReference URI="#ED38"/></></></>                         # N.B. hash
     709                 :            :  *
     710                 :            :  * Alternative formulation is to replace the EncryptedData/KeyInfo/RetrievalMethod
     711                 :            :  * with EncryptedData/KeyInfo/EncryptedKey, i.e. inline the EncryptedKey. As of 2010
     712                 :            :  * Shibboleth appears to support only this method.
     713                 :            :  */
     714                 :            : 
     715                 :            : /* Called by:  zxenc_pubkey_enc */
     716                 :            : struct zx_xenc_EncryptedData_s* zxenc_symkey_enc(zxid_conf* cf, struct zx_str* data, struct zx_str* ed_id, struct zx_str* symkey, struct zx_xenc_EncryptedKey_s* ek)
     717                 :        957 : {
     718                 :            :   struct zx_str* ss;
     719                 :            :   struct zx_str* b64;
     720                 :        957 :   struct zx_xenc_EncryptedData_s* ed = zx_NEW_xenc_EncryptedData(cf->ctx,0);
     721                 :        957 :   ed->Id = zx_ref_len_attr(cf->ctx, &ed->gg, zx_Id_ATTR, ed_id->len, ed_id->s);
     722                 :        957 :   ed->Type = zx_ref_attr(cf->ctx, &ed->gg, zx_Type_ATTR, "http://www.w3.org/2001/04/xmlenc#Element");
     723                 :        957 :   ed->EncryptionMethod = zx_NEW_xenc_EncryptionMethod(cf->ctx, &ed->gg);
     724                 :        957 :   ed->EncryptionMethod->Algorithm = zx_ref_attr(cf->ctx, &ed->EncryptionMethod->gg, zx_Algorithm_ATTR, ENC_ALGO);
     725         [ +  - ]:        957 :   if (ek) {
     726                 :        957 :     ed->KeyInfo = zx_NEW_ds_KeyInfo(cf->ctx, &ed->gg);
     727         [ +  - ]:        957 :     if (cf->enckey_opt & 0x20) {
     728   [ +  +  -  + ]:        957 :       D("Nested EncryptedKey %p", ek); /* Shibboleth early 2010 */
     729                 :        957 :       ZX_ADD_KID(ed->KeyInfo, EncryptedKey, ek);
     730                 :            :     } else {
     731   [ #  #  #  # ]:          0 :       D("Sibling EncryptedKey with RetrievalMethod %p", ek);
     732                 :          0 :       ed->KeyInfo->RetrievalMethod = zx_NEW_ds_RetrievalMethod(cf->ctx, &ed->KeyInfo->gg);
     733                 :          0 :       ed->KeyInfo->RetrievalMethod->Type = zx_ref_attr(cf->ctx, &ed->KeyInfo->RetrievalMethod->gg, zx_Type_ATTR, "http://www.w3.org/2001/04/xmlenc#EncryptedKey");
     734                 :          0 :       ed->KeyInfo->RetrievalMethod->URI = zx_attrf(cf->ctx, &ed->KeyInfo->RetrievalMethod->gg, zx_URI_ATTR, "#%.*s", ek->Id->g.len, ek->Id->g.s);
     735                 :            :     }
     736                 :            :   }
     737                 :            :   DD("Plaintext(%.*s)", data->len, data->s);
     738                 :        957 :   D_XML_BLOB(cf, "PLAINTEXT", data->len, data->s);
     739                 :        957 :   ss = zx_raw_cipher(cf->ctx, "AES-128-CBC", 1, symkey, data->len, data->s, 16, 0);
     740                 :        957 :   b64 = zx_new_len_str(cf->ctx, SIMPLE_BASE64_LEN(ss->len));
     741                 :        957 :   base64_fancy_raw(ss->s, ss->len, b64->s, std_basis_64, 0, 0, 0, '=');
     742                 :        957 :   zx_str_free(cf->ctx, ss);
     743                 :        957 :   ed->CipherData = zx_NEW_xenc_CipherData(cf->ctx, &ed->gg);
     744                 :        957 :   ed->CipherData->CipherValue = zx_new_str_elem(cf->ctx, &ed->CipherData->gg, zx_xenc_CipherValue_ELEM, b64);
     745                 :        957 :   zx_reverse_elem_lists(&ed->gg);
     746                 :        957 :   return ed;
     747                 :            : }
     748                 :            : 
     749                 :            : /*() Public key encryption using XML-ENC. The encryption algorithm is
     750                 :            :  * auto-detected from the XML-ENC data.
     751                 :            :  *
     752                 :            :  * cf:: ZXID configuration object, used for memory allocation
     753                 :            :  * data:: Data blob to encrypt. Typically serialized XML
     754                 :            :  * ekp:: Result parameter. XML data structure corresponding to the <EncryptedKey>
     755                 :            :  *     element will be returned. This is the encrypted symmetric key (which is
     756                 :            :  *     pseudorandom generated inside this function). Usually used to set EncryptedKey
     757                 :            :  *     field of EncryptedAssertion when using sister elements, aka RetrievalMethod, approach.
     758                 :            :  *     When using nested EncryptedKey (Shib 2010) approach, leave null.
     759                 :            :  * cert:: Certificate containing the public key used to encrypt the symmetric key
     760                 :            :  * idsuffix:: Use to generate XML ~Id~ attributes for <EncryptedKey> and <EncryptedData>
     761                 :            :  * return:: Encrypted data as XML data structure. Caller should free this memory. */
     762                 :            : 
     763                 :            : /* Called by:  zxid_mk_enc_a7n x2, zxid_mk_enc_id x2, zxid_mk_mni x2 */
     764                 :            : struct zx_xenc_EncryptedData_s* zxenc_pubkey_enc(zxid_conf* cf, struct zx_str* data, struct zx_xenc_EncryptedKey_s** ekp, X509* cert, char* idsuffix, zxid_entity* meta)
     765                 :        957 : {
     766                 :            :   struct rsa_st* rsa_pkey;
     767                 :            :   char symkey[128/8];
     768                 :            :   struct zx_str symkey_ss;
     769                 :            :   struct zx_str* ss;
     770                 :            :   struct zx_str* b64;
     771                 :        957 :   struct zx_xenc_EncryptedKey_s* ek = zx_NEW_xenc_EncryptedKey(cf->ctx,0);
     772                 :            :   
     773                 :        957 :   ek->Id = zx_attrf(cf->ctx, &ek->gg, zx_Id_ATTR, "EK%s", idsuffix);
     774                 :        957 :   ek->EncryptionMethod = zx_NEW_xenc_EncryptionMethod(cf->ctx, &ek->gg);
     775                 :        957 :   ek->EncryptionMethod->Algorithm = zx_ref_attr(cf->ctx, &ek->EncryptionMethod->gg, zx_Algorithm_ATTR, ENC_KEYTRAN_ALGO);
     776                 :        957 :   ek->KeyInfo = zxid_key_info(cf, &ek->gg, cert);
     777   [ -  +  #  # ]:        957 :   if (meta && cf->enckey_opt & 0x01) {
     778                 :            :     /* This hack may help early 2010 vintage Shibboleth SP to work without nested EncryptedKey.
     779                 :            :      * (personal communication w/Scott 20100906 --Sampo) */
     780                 :          0 :     ek->Recipient = zx_dup_attr(cf->ctx, &ek->gg, zx_Recipient_ATTR, meta->eid);
     781                 :            :   }
     782                 :            :   
     783                 :        957 :   zx_rand(symkey, sizeof(symkey));
     784                 :        957 :   symkey_ss.len = sizeof(symkey);
     785                 :        957 :   symkey_ss.s = symkey;
     786                 :        957 :   rsa_pkey = zx_get_rsa_pub_from_cert(cert, "zxenc_pubkey_enc");
     787         [ -  + ]:        957 :   if (!rsa_pkey)
     788                 :          0 :     return 0;
     789                 :            :   /* The padding setting MUST agree with ENC_KEYTRAN_ALGO setting (see near top of this file). */
     790                 :            : #if 1
     791                 :        957 :   ss = zx_rsa_pub_enc(cf->ctx, &symkey_ss, rsa_pkey, RSA_PKCS1_PADDING);
     792                 :            : #else
     793                 :            :   /* *** IBM did not interop with OAEP padding as of 20071025 */
     794                 :            :   ss = zx_rsa_pub_enc(cf->ctx, &symkey_ss, rsa_pkey, RSA_PKCS1_OAEP_PADDING);
     795                 :            : #endif
     796                 :            :   
     797                 :        957 :   b64 = zx_new_len_str(cf->ctx, SIMPLE_BASE64_LEN(ss->len));
     798                 :        957 :   base64_fancy_raw(ss->s, ss->len, b64->s, std_basis_64, 0, 0, 0, '=');
     799                 :        957 :   zx_str_free(cf->ctx, ss);
     800                 :        957 :   ek->CipherData = zx_NEW_xenc_CipherData(cf->ctx, &ek->gg);
     801                 :        957 :   ek->CipherData->CipherValue = zx_new_str_elem(cf->ctx, &ek->CipherData->gg, zx_xenc_CipherValue_ELEM, b64);
     802                 :        957 :   ek->ReferenceList = zx_NEW_xenc_ReferenceList(cf->ctx, &ek->gg);
     803                 :        957 :   ek->ReferenceList->DataReference = zx_NEW_xenc_DataReference(cf->ctx, &ek->ReferenceList->gg);
     804                 :        957 :   ek->ReferenceList->DataReference->URI = zx_attrf(cf->ctx, &ek->ReferenceList->DataReference->gg, zx_URI_ATTR, "#ED%s", idsuffix);
     805                 :        957 :   zx_reverse_elem_lists(&ek->gg);
     806         [ -  + ]:        957 :   if (ekp)
     807                 :          0 :     *ekp = ek;
     808                 :            :   
     809                 :        957 :   ss = zx_strf(cf->ctx, "ED%s", idsuffix);
     810                 :        957 :   return zxenc_symkey_enc(cf, data, ss, &symkey_ss, ek);
     811                 :            : }
     812                 :            : 
     813                 :            : /* EOF -- zxsig.c */

Generated by: LCOV version 1.9