LCOV - code coverage report
Current view: top level - src - vcard_emul_nss.c (source / functions) Hit Total Coverage
Test: Code coverage Lines: 418 542 77.1 %
Date: 2023-06-12 11:14:12 Functions: 31 33 93.9 %
Legend: Lines: hit not hit | Branches: + taken - not taken # not executed Branches: 187 338 55.3 %

           Branch data     Line data    Source code
       1                 :            : /*
       2                 :            :  * This is the actual card emulator.
       3                 :            :  *
       4                 :            :  * These functions can be implemented in different ways on different platforms
       5                 :            :  * using the underlying system primitives. For Linux it uses NSS, though direct
       6                 :            :  * to PKCS #11, openssl+pkcs11, or even gnu crypto libraries+pkcs #11 could be
       7                 :            :  * used. On Windows CAPI could be used.
       8                 :            :  *
       9                 :            :  * This work is licensed under the terms of the GNU LGPL, version 2.1 or later.
      10                 :            :  * See the COPYING file in the top-level directory.
      11                 :            :  */
      12                 :            : #include "config.h"
      13                 :            : 
      14                 :            : #include <glib.h>
      15                 :            : 
      16                 :            : #include "common.h"
      17                 :            : 
      18                 :            : /*
      19                 :            :  * NSS headers
      20                 :            :  */
      21                 :            : 
      22                 :            : /* avoid including prototypes.h that redefines uint32 */
      23                 :            : #define NO_NSPR_10_SUPPORT
      24                 :            : 
      25                 :            : #include <nss.h>
      26                 :            : #include <pk11pub.h>
      27                 :            : #include <cert.h>
      28                 :            : #include <keyhi.h>
      29                 :            : #include <secmod.h>
      30                 :            : #include <prthread.h>
      31                 :            : #include <secerr.h>
      32                 :            : #include <secoid.h>
      33                 :            : #include <secmodt.h>
      34                 :            : #include <sechash.h>
      35                 :            : 
      36                 :            : #include "vcard.h"
      37                 :            : #include "card_7816t.h"
      38                 :            : #include "vcard_emul.h"
      39                 :            : #include "vreader.h"
      40                 :            : #include "vevent.h"
      41                 :            : 
      42                 :            : #include "vcardt_internal.h"
      43                 :            : #if defined(ENABLE_PCSC)
      44                 :            : #include "capcsc.h"
      45                 :            : #endif
      46                 :            : 
      47                 :            : 
      48                 :            : typedef enum {
      49                 :            :     VCardEmulUnknown = -1,
      50                 :            :     VCardEmulFalse = 0,
      51                 :            :     VCardEmulTrue = 1
      52                 :            : } VCardEmulTriState;
      53                 :            : 
      54                 :            : struct VCardKeyStruct {
      55                 :            :     CERTCertificate *cert;
      56                 :            :     PK11SlotInfo *slot;
      57                 :            :     VCardEmulTriState failedX509;
      58                 :            : };
      59                 :            : 
      60                 :            : 
      61                 :            : typedef struct VirtualReaderOptionsStruct VirtualReaderOptions;
      62                 :            : 
      63                 :            : struct VReaderEmulStruct {
      64                 :            :     PK11SlotInfo *slot;
      65                 :            :     VCardEmulType default_type;
      66                 :            :     char *type_params;
      67                 :            :     PRBool present;
      68                 :            :     int     series;
      69                 :            :     VCard *saved_vcard;
      70                 :            : };
      71                 :            : 
      72                 :            : /*
      73                 :            :  *  NSS Specific options
      74                 :            :  */
      75                 :            : struct VirtualReaderOptionsStruct {
      76                 :            :     char *name;
      77                 :            :     char *vname;
      78                 :            :     VCardEmulType card_type;
      79                 :            :     char *type_params;
      80                 :            :     char **cert_name;
      81                 :            :     int cert_count;
      82                 :            : };
      83                 :            : 
      84                 :            : enum {
      85                 :            :     USE_HW_NO,
      86                 :            :     USE_HW_YES,
      87                 :            :     USE_HW_REMOVABLE,
      88                 :            : };
      89                 :            : 
      90                 :            : struct VCardEmulOptionsStruct {
      91                 :            :     char *nss_db;
      92                 :            :     VirtualReaderOptions *vreader;
      93                 :            :     int vreader_count;
      94                 :            :     VCardEmulType hw_card_type;
      95                 :            :     char *hw_type_params;
      96                 :            :     int use_hw;
      97                 :            : };
      98                 :            : 
      99                 :            : static int nss_emul_init;
     100                 :            : 
     101                 :            : /* if we have more that just the slot, define
     102                 :            :  * VCardEmulStruct here */
     103                 :            : 
     104                 :            : /*
     105                 :            :  * allocate the set of arrays for certs, cert_len, key
     106                 :            :  */
     107                 :            : static void
     108                 :          6 : vcard_emul_alloc_arrays(unsigned char ***certsp, int **cert_lenp,
     109                 :            :                         VCardKey ***keysp, int cert_count)
     110                 :            : {
     111   [ -  +  -  - ]:          6 :     *certsp = g_new(unsigned char *, cert_count);
     112   [ -  +  -  - ]:          6 :     *cert_lenp = g_new(int, cert_count);
     113   [ -  +  -  - ]:          6 :     *keysp = g_new(VCardKey *, cert_count);
     114                 :          6 : }
     115                 :            : 
     116                 :            : /*
     117                 :            :  * Emulator specific card information
     118                 :            :  */
     119                 :            : typedef struct CardEmulCardStruct CardEmulPrivate;
     120                 :            : 
     121                 :            : static VCardEmul *
     122                 :            : vcard_emul_new_card(PK11SlotInfo *slot)
     123                 :            : {
     124                 :          6 :     PK11_ReferenceSlot(slot);
     125                 :            :     /* currently we don't need anything other than the slot */
     126                 :            :     return (VCardEmul *)slot;
     127                 :            : }
     128                 :            : 
     129                 :            : static void
     130                 :          5 : vcard_emul_delete_card(VCardEmul *vcard_emul)
     131                 :            : {
     132                 :            :     PK11SlotInfo *slot = (PK11SlotInfo *)vcard_emul;
     133         [ +  - ]:          5 :     if (slot == NULL) {
     134                 :            :         return;
     135                 :            :     }
     136                 :          5 :     PK11_FreeSlot(slot);
     137                 :            : }
     138                 :            : 
     139                 :            : static PK11SlotInfo *
     140                 :            : vcard_emul_card_get_slot(VCard *card)
     141                 :            : {
     142                 :            :     /* note, the card is holding the reference, no need to get another one */
     143                 :        118 :     return (PK11SlotInfo *)vcard_get_private(card);
     144                 :            : }
     145                 :            : 
     146                 :            : 
     147                 :            : /*
     148                 :            :  * key functions
     149                 :            :  */
     150                 :            : /* private constructure */
     151                 :            : static VCardKey *
     152                 :         16 : vcard_emul_make_key(PK11SlotInfo *slot, CERTCertificate *cert)
     153                 :            : {
     154                 :            :     VCardKey *key;
     155                 :            : 
     156                 :         16 :     key = g_new(VCardKey, 1);
     157                 :         16 :     key->slot = PK11_ReferenceSlot(slot);
     158                 :         16 :     key->cert = CERT_DupCertificate(cert);
     159                 :         16 :     key->failedX509 = VCardEmulUnknown;
     160                 :         16 :     return key;
     161                 :            : }
     162                 :            : 
     163                 :            : /* destructor */
     164                 :            : void
     165                 :         13 : vcard_emul_delete_key(VCardKey *key)
     166                 :            : {
     167   [ +  -  +  - ]:         13 :     if (!nss_emul_init || (key == NULL)) {
     168                 :            :         return;
     169                 :            :     }
     170         [ +  - ]:         13 :     if (key->cert) {
     171                 :         13 :         CERT_DestroyCertificate(key->cert);
     172                 :            :     }
     173         [ +  - ]:         13 :     if (key->slot) {
     174                 :         13 :         PK11_FreeSlot(key->slot);
     175                 :            :     }
     176                 :         13 :     g_free(key);
     177                 :            : }
     178                 :            : 
     179                 :            : /*
     180                 :            :  * grab the nss key from a VCardKey. If it doesn't exist, try to look it up
     181                 :            :  */
     182                 :            : static SECKEYPrivateKey *
     183                 :            : vcard_emul_get_nss_key(VCardKey *key)
     184                 :            : {
     185                 :            :     /* NOTE: if we aren't logged into the token, this could return NULL */
     186                 :         36 :     return PK11_FindPrivateKeyFromCert(key->slot, key->cert, NULL);
     187                 :            : }
     188                 :            : 
     189                 :            : /*
     190                 :            :  * Map NSS errors to 7816 errors
     191                 :            :  */
     192                 :            : static vcard_7816_status_t
     193                 :          1 : vcard_emul_map_error(int error)
     194                 :            : {
     195   [ +  -  -  - ]:          1 :     switch (error) {
     196                 :            :     case SEC_ERROR_TOKEN_NOT_LOGGED_IN:
     197                 :            :         return VCARD7816_STATUS_ERROR_CONDITION_NOT_SATISFIED;
     198                 :          1 :     case SEC_ERROR_BAD_DATA:
     199                 :            :     case SEC_ERROR_OUTPUT_LEN:
     200                 :            :     case SEC_ERROR_INPUT_LEN:
     201                 :            :     case SEC_ERROR_INVALID_ARGS:
     202                 :            :     case SEC_ERROR_INVALID_ALGORITHM:
     203                 :            :     case SEC_ERROR_NO_KEY:
     204                 :            :     case SEC_ERROR_INVALID_KEY:
     205                 :            :     case SEC_ERROR_DECRYPTION_DISALLOWED:
     206                 :            :     case SEC_ERROR_PKCS11_GENERAL_ERROR:
     207                 :          1 :         return VCARD7816_STATUS_ERROR_DATA_INVALID;
     208                 :          0 :     case SEC_ERROR_NO_MEMORY:
     209                 :          0 :         return VCARD7816_STATUS_EXC_ERROR_MEMORY_FAILURE;
     210                 :          0 :     default:
     211                 :          0 :         g_debug("error %x", 0x2000 + error);
     212                 :          0 :         g_warn_if_reached();
     213                 :            :     }
     214                 :          0 :     return VCARD7816_STATUS_EXC_ERROR_CHANGE;
     215                 :            : }
     216                 :            : 
     217                 :            : /* get RSA bits */
     218                 :            : int
     219                 :         16 : vcard_emul_rsa_bits(VCardKey *key)
     220                 :            : {
     221                 :            :     SECKEYPublicKey *pub_key;
     222                 :            :     int bits = -1;
     223                 :            : 
     224         [ -  + ]:         16 :     if (key == NULL) {
     225                 :            :         /* couldn't get the key, indicate that we aren't logged in */
     226                 :            :         return -1;
     227                 :            :     }
     228                 :         16 :     pub_key = CERT_ExtractPublicKey(key->cert);
     229         [ -  + ]:         16 :     if (pub_key == NULL) {
     230                 :            :         /* couldn't get the key, indicate that we aren't logged in */
     231                 :            :         return -1;
     232                 :            :     }
     233                 :            : 
     234                 :         16 :     bits = SECKEY_PublicKeyStrengthInBits(pub_key);
     235                 :         16 :     SECKEY_DestroyPublicKey(pub_key);
     236                 :         16 :     return bits;
     237                 :            : }
     238                 :            : 
     239                 :            : /* RSA sign/decrypt with the key, signature happens 'in place' */
     240                 :            : vcard_7816_status_t
     241                 :         36 : vcard_emul_rsa_op(VCard *card, VCardKey *key,
     242                 :            :                   unsigned char *buffer, int buffer_size)
     243                 :            : {
     244                 :            :     SECKEYPrivateKey *priv_key;
     245                 :            :     unsigned signature_len;
     246                 :            :     PK11SlotInfo *slot;
     247                 :            :     SECStatus rv;
     248                 :            :     unsigned char buf[2048];
     249                 :            :     unsigned char *bp = NULL;
     250                 :            :     int pad_len;
     251                 :            :     vcard_7816_status_t ret = VCARD7816_STATUS_SUCCESS;
     252                 :            : 
     253         [ -  + ]:         36 :     assert(buffer_size >= 0);
     254   [ +  -  -  + ]:         36 :     if ((!nss_emul_init) || (key == NULL)) {
     255                 :            :         /* couldn't get the key, indicate that we aren't logged in */
     256                 :            :         return VCARD7816_STATUS_ERROR_CONDITION_NOT_SATISFIED;
     257                 :            :     }
     258                 :            :     priv_key = vcard_emul_get_nss_key(key);
     259         [ -  + ]:         36 :     if (priv_key == NULL) {
     260                 :            :         /* couldn't get the key, indicate that we aren't logged in */
     261                 :            :         return VCARD7816_STATUS_ERROR_CONDITION_NOT_SATISFIED;
     262                 :            :     }
     263                 :            :     slot = vcard_emul_card_get_slot(card);
     264                 :            : 
     265                 :            :     /*
     266                 :            :      * this is only true of the rsa signature
     267                 :            :      */
     268                 :         36 :     signature_len = PK11_SignatureLen(priv_key);
     269         [ -  + ]:         36 :     if ((unsigned)buffer_size != signature_len) {
     270                 :            :         ret = VCARD7816_STATUS_ERROR_DATA_INVALID;
     271                 :          0 :         goto cleanup;
     272                 :            :     }
     273                 :            :     /* be able to handle larger keys if necessary */
     274                 :            :     bp = &buf[0];
     275         [ -  + ]:         36 :     if (sizeof(buf) < signature_len) {
     276                 :          0 :         bp = g_malloc(signature_len);
     277                 :            :     }
     278                 :            : 
     279                 :            :     /*
     280                 :            :      * do the raw operations. Some tokens claim to do CKM_RSA_X_509, but then
     281                 :            :      * choke when they try to do the actual operations. Try to detect
     282                 :            :      * those cases and treat them as if the token didn't claim support for
     283                 :            :      * X_509.
     284                 :            :      */
     285         [ +  + ]:         36 :     if (key->failedX509 != VCardEmulTrue
     286         [ +  + ]:         23 :                               && PK11_DoesMechanism(slot, CKM_RSA_X_509)) {
     287                 :         21 :         rv = PK11_PrivDecryptRaw(priv_key, bp, &signature_len, signature_len,
     288                 :            :                                  buffer, buffer_size);
     289         [ +  - ]:         21 :         if (rv == SECSuccess) {
     290         [ -  + ]:         21 :             assert((unsigned)buffer_size == signature_len);
     291                 :         21 :             memcpy(buffer, bp, signature_len);
     292                 :         21 :             key->failedX509 = VCardEmulFalse;
     293                 :         21 :             goto cleanup;
     294                 :            :         }
     295                 :            :         /*
     296                 :            :          * we've had a successful X509 operation, this failure must be
     297                 :            :          * something else
     298                 :            :          */
     299         [ #  # ]:          0 :         if (key->failedX509 == VCardEmulFalse) {
     300                 :          0 :             ret = vcard_emul_map_error(PORT_GetError());
     301                 :          0 :             goto cleanup;
     302                 :            :         }
     303                 :            :         /*
     304                 :            :          * key->failedX509 must be Unknown at this point, try the
     305                 :            :          * non-x_509 case
     306                 :            :          */
     307                 :            :     }
     308                 :            :     /* token does not support CKM_RSA_X509, emulate that with CKM_RSA_PKCS */
     309                 :            :     /* is this a PKCS #1 formatted signature? */
     310   [ +  +  +  + ]:         15 :     if ((buffer[0] == 0) && (buffer[1] == 1)) {
     311                 :            :         int i;
     312                 :            : 
     313         [ +  - ]:       1926 :         for (i = 2; i < buffer_size; i++) {
     314                 :            :             /* rsa signature pad */
     315         [ +  + ]:       1926 :             if (buffer[i] != 0xff) {
     316                 :            :                 break;
     317                 :            :             }
     318                 :            :         }
     319   [ +  -  +  - ]:         12 :         if ((i < buffer_size) && (buffer[i] == 0)) {
     320                 :            :             /* yes, we have a properly formatted PKCS #1 signature */
     321                 :            :             /*
     322                 :            :              * NOTE: even if we accidentally got an encrypt buffer, which
     323                 :            :              * through sheer luck started with 00, 01, ff, 00, it won't matter
     324                 :            :              * because the resulting Sign operation will effectively decrypt
     325                 :            :              * the real buffer.
     326                 :            :              */
     327                 :            :             SECItem signature;
     328                 :            :             SECItem hash;
     329                 :            : 
     330                 :         12 :             i++;
     331                 :         12 :             hash.data = &buffer[i];
     332                 :         12 :             hash.len = buffer_size - i;
     333                 :         12 :             signature.data = bp;
     334                 :         12 :             signature.len = signature_len;
     335                 :         12 :             rv = PK11_Sign(priv_key,  &signature, &hash);
     336         [ -  + ]:         12 :             if (rv != SECSuccess) {
     337                 :          0 :                 ret = vcard_emul_map_error(PORT_GetError());
     338                 :          0 :                 goto cleanup;
     339                 :            :             }
     340         [ -  + ]:         12 :             assert((unsigned)buffer_size == signature.len);
     341                 :         12 :             memcpy(buffer, bp, signature.len);
     342                 :            :             /*
     343                 :            :              * we got here because either the X509 attempt failed, or the
     344                 :            :              * token couldn't do the X509 operation, in either case stay
     345                 :            :              * with the PKCS version for future operations on this key
     346                 :            :              */
     347                 :         12 :             key->failedX509 = VCardEmulTrue;
     348                 :         12 :             goto cleanup;
     349                 :            :         }
     350                 :            :     }
     351                 :            :     /* We can not do raw RSA operation and the bytes do not look like PKCS#1.5
     352                 :            :      * Assuming it is deciphering operation.
     353                 :            :      */
     354                 :          3 :     rv = PK11_PrivDecryptPKCS1(priv_key, bp, &signature_len, buffer_size, buffer, buffer_size);
     355         [ +  + ]:          3 :     if (rv != SECSuccess) {
     356                 :            :         /* The assumption was wrong. Give up */
     357                 :          1 :         ret = vcard_emul_map_error(PORT_GetError());
     358                 :          1 :         goto cleanup;
     359                 :            :     }
     360                 :          2 :     pad_len = buffer_size - signature_len;
     361         [ -  + ]:          2 :     if (pad_len < 4) {
     362                 :            :         ret = VCARD7816_STATUS_ERROR_GENERAL;
     363                 :          0 :         goto cleanup;
     364                 :            :     }
     365                 :            :     /*
     366                 :            :      * OK now we've decrypted the payload, package it up in PKCS #1 for the
     367                 :            :      * upper layer.
     368                 :            :      */
     369                 :          2 :     buffer[0] = 0;
     370                 :          2 :     buffer[1] = 2; /* RSA_encrypt  */
     371                 :          2 :     pad_len -= 3; /* format is 0 || 2 || pad || 0 || data */
     372                 :            :     /*
     373                 :            :      * padding for PKCS #1 encrypted data is a string of random bytes. The
     374                 :            :      * random bytes protect against potential decryption attacks against RSA.
     375                 :            :      * Since PrivDecrypt has already stripped those bytes, we can't reconstruct
     376                 :            :      * them. This shouldn't matter to the upper level code which should just
     377                 :            :      * strip this code out anyway, so We'll pad with a constant 3.
     378                 :            :      */
     379                 :          2 :     memset(&buffer[2], 0x03, pad_len);
     380                 :          2 :     pad_len += 2; /* index to the end of the pad */
     381                 :          2 :     buffer[pad_len] = 0;
     382                 :            :     pad_len++; /* index to the start of the data */
     383                 :          2 :     memcpy(&buffer[pad_len], bp, signature_len);
     384                 :            :     /*
     385                 :            :      * we got here because either the X509 attempt failed, or the
     386                 :            :      * token couldn't do the X509 operation, in either case stay
     387                 :            :      * with the PKCS version for future operations on this key
     388                 :            :      */
     389                 :          2 :     key->failedX509 = VCardEmulTrue;
     390                 :         36 : cleanup:
     391         [ -  + ]:         36 :     if (bp != buf) {
     392                 :          0 :         g_free(bp);
     393                 :            :     }
     394                 :         36 :     SECKEY_DestroyPrivateKey(priv_key);
     395                 :         36 :     return ret;
     396                 :            : }
     397                 :            : 
     398                 :            : /*
     399                 :            :  * Login functions
     400                 :            :  */
     401                 :            : /* return the number of login attempts still possible on the card. if unknown,
     402                 :            :  * return -1 */
     403                 :            : int
     404                 :          4 : vcard_emul_get_login_count(G_GNUC_UNUSED VCard *card)
     405                 :            : {
     406                 :          4 :     return -1;
     407                 :            : }
     408                 :            : 
     409                 :            : /* login into the card, return the 7816 status word (sw2 || sw1) */
     410                 :            : vcard_7816_status_t
     411                 :         20 : vcard_emul_login(VCard *card, unsigned char *pin, int pin_len)
     412                 :            : {
     413                 :            :     PK11SlotInfo *slot;
     414                 :            :     unsigned char *pin_string;
     415                 :            :     int i;
     416                 :            :     SECStatus rv;
     417                 :            : 
     418         [ -  + ]:         20 :     if (!nss_emul_init) {
     419                 :            :         return VCARD7816_STATUS_ERROR_CONDITION_NOT_SATISFIED;
     420                 :            :     }
     421                 :            :     slot = vcard_emul_card_get_slot(card);
     422                 :            :      /* We depend on the PKCS #11 module internal login state here because we
     423                 :            :       * create a separate process to handle each guest instance. If we needed
     424                 :            :       * to handle multiple guests from one process, then we would need to keep
     425                 :            :       * a lot of extra state in our card structure
     426                 :            :       * */
     427                 :         20 :     pin_string = g_malloc(pin_len+1);
     428                 :         20 :     memcpy(pin_string, pin, pin_len);
     429                 :         20 :     pin_string[pin_len] = 0;
     430                 :            : 
     431                 :            :     /* handle CAC expanded pins correctly */
     432   [ +  +  +  + ]:         44 :     for (i = pin_len-1; i >= 0 && (pin_string[i] == 0xff); i--) {
     433                 :         24 :         pin_string[i] = 0;
     434                 :            :     }
     435                 :            : 
     436                 :            :     /* If using an emulated card, make sure to log out of any already logged in
     437                 :            :      * session. */
     438                 :         20 :     vcard_emul_logout(card);
     439                 :            : 
     440                 :         20 :     rv = PK11_Authenticate(slot, PR_FALSE, pin_string);
     441                 :         20 :     memset(pin_string, 0, pin_len);  /* don't let the pin hang around in memory
     442                 :            :                                         to be snooped */
     443                 :         20 :     g_free(pin_string);
     444         [ -  + ]:         20 :     if (rv == SECSuccess) {
     445                 :            :         return VCARD7816_STATUS_SUCCESS;
     446                 :            :     }
     447                 :            :     /* map the error from port get error */
     448                 :            :     return VCARD7816_STATUS_ERROR_CONDITION_NOT_SATISFIED;
     449                 :            : }
     450                 :            : 
     451                 :            : int
     452                 :         26 : vcard_emul_is_logged_in(VCard *card)
     453                 :            : {
     454                 :            :     PK11SlotInfo *slot;
     455                 :            : 
     456         [ +  - ]:         26 :     if (!nss_emul_init) {
     457                 :            :         return VCARD7816_STATUS_ERROR_CONDITION_NOT_SATISFIED;
     458                 :            :     }
     459                 :            : 
     460                 :            :     slot = vcard_emul_card_get_slot(card);
     461                 :            :      /* We depend on the PKCS #11 module internal login state here because we
     462                 :            :       * create a separate process to handle each guest instance. If we needed
     463                 :            :       * to handle multiple guests from one process, then we would need to keep
     464                 :            :       * a lot of extra state in our card structure
     465                 :            :       */
     466                 :            : 
     467                 :            :     /* If we do not need log in, we present the token as "logged in" */
     468         [ +  + ]:         26 :     if (PK11_NeedLogin(slot) == PR_FALSE) {
     469                 :            :         return 1;
     470                 :            :     }
     471                 :            : 
     472                 :            :     /* For the tokens that require login, delegate to NSS to figure out the
     473                 :            :      * login status */
     474                 :         20 :     return !!PK11_IsLoggedIn(slot, NULL);
     475                 :            : }
     476                 :            : 
     477                 :            : void
     478                 :         36 : vcard_emul_logout(VCard *card)
     479                 :            : {
     480                 :            :     PK11SlotInfo *slot;
     481                 :            : 
     482         [ +  - ]:         36 :     if (!nss_emul_init) {
     483                 :            :         return;
     484                 :            :     }
     485                 :            : 
     486                 :            :     slot = vcard_emul_card_get_slot(card);
     487         [ +  + ]:         36 :     if (PK11_IsLoggedIn(slot, NULL)) {
     488                 :         14 :         PK11_Logout(slot); /* NOTE: ignoring SECStatus return value */
     489                 :            :     }
     490                 :            : }
     491                 :            : 
     492                 :            : void
     493                 :         16 : vcard_emul_reset(VCard *card, G_GNUC_UNUSED VCardPower power)
     494                 :            : {
     495                 :            :     /*
     496                 :            :      * if we reset the card (either power on or power off), we lose our login
     497                 :            :      * state
     498                 :            :      */
     499                 :         16 :     vcard_emul_logout(card);
     500                 :            : 
     501                 :            :     /* TODO: we may also need to send insertion/removal events? */
     502                 :         16 : }
     503                 :            : 
     504                 :            : static VReader *
     505                 :          4 : vcard_emul_find_vreader_from_slot(PK11SlotInfo *slot)
     506                 :            : {
     507                 :          4 :     VReaderList *reader_list = vreader_get_reader_list();
     508                 :            :     VReaderListEntry *current_entry;
     509                 :            : 
     510         [ -  + ]:          4 :     if (reader_list == NULL) {
     511                 :            :         return NULL;
     512                 :            :     }
     513         [ +  - ]:          6 :     for (current_entry = vreader_list_get_first(reader_list); current_entry;
     514                 :          2 :                         current_entry = vreader_list_get_next(current_entry)) {
     515                 :          6 :         VReader *reader = vreader_list_get_reader(current_entry);
     516                 :          6 :         VReaderEmul *reader_emul = vreader_get_private(reader);
     517         [ +  + ]:          6 :         if (reader_emul->slot == slot) {
     518                 :          4 :             vreader_list_delete(reader_list);
     519                 :          4 :             return reader;
     520                 :            :         }
     521                 :          2 :         vreader_free(reader);
     522                 :            :     }
     523                 :            : 
     524                 :          0 :     vreader_list_delete(reader_list);
     525                 :          0 :     return NULL;
     526                 :            : }
     527                 :            : 
     528                 :            : /*
     529                 :            :  * create a new reader emul
     530                 :            :  */
     531                 :            : static VReaderEmul *
     532                 :          8 : vreader_emul_new(PK11SlotInfo *slot, VCardEmulType type, const char *params)
     533                 :            : {
     534                 :            :     VReaderEmul *new_reader_emul;
     535                 :            : 
     536                 :          8 :     new_reader_emul = g_new(VReaderEmul, 1);
     537                 :            : 
     538                 :          8 :     new_reader_emul->slot = PK11_ReferenceSlot(slot);
     539                 :          8 :     new_reader_emul->default_type = type;
     540                 :          8 :     new_reader_emul->type_params = g_strdup(params);
     541                 :          8 :     new_reader_emul->present = PR_FALSE;
     542                 :          8 :     new_reader_emul->series = 0;
     543                 :          8 :     new_reader_emul->saved_vcard = NULL;
     544                 :          8 :     return new_reader_emul;
     545                 :            : }
     546                 :            : 
     547                 :            : static void
     548                 :          5 : vreader_emul_delete(VReaderEmul *vreader_emul)
     549                 :            : {
     550         [ +  - ]:          5 :     if (vreader_emul == NULL) {
     551                 :            :         return;
     552                 :            :     }
     553                 :          5 :     vcard_free(vreader_emul->saved_vcard);
     554         [ +  - ]:          5 :     if (vreader_emul->slot) {
     555                 :          5 :         PK11_FreeSlot(vreader_emul->slot);
     556                 :            :     }
     557                 :          5 :     g_free(vreader_emul->type_params);
     558                 :          5 :     g_free(vreader_emul);
     559                 :            : }
     560                 :            : 
     561                 :            : /*
     562                 :            :  *  TODO: move this to emulater non-specific file
     563                 :            :  */
     564                 :            : static VCardEmulType
     565                 :          6 : vcard_emul_get_type(VReader *vreader)
     566                 :            : {
     567                 :            :     VReaderEmul *vreader_emul;
     568                 :            : 
     569                 :          6 :     vreader_emul = vreader_get_private(vreader);
     570   [ +  -  -  + ]:          6 :     if (vreader_emul && vreader_emul->default_type != VCARD_EMUL_NONE) {
     571                 :            :         return vreader_emul->default_type;
     572                 :            :     }
     573                 :            : 
     574                 :          0 :     return vcard_emul_type_select(vreader);
     575                 :            : }
     576                 :            : /*
     577                 :            :  *  TODO: move this to emulater non-specific file
     578                 :            :  */
     579                 :            : static const char *
     580                 :            : vcard_emul_get_type_params(VReader *vreader)
     581                 :            : {
     582                 :            :     VReaderEmul *vreader_emul;
     583                 :            : 
     584                 :          6 :     vreader_emul = vreader_get_private(vreader);
     585   [ -  +  +  + ]:          6 :     if (vreader_emul && vreader_emul->type_params) {
     586                 :            :         return vreader_emul->type_params;
     587                 :            :     }
     588                 :            : 
     589                 :            :     return "";
     590                 :            : }
     591                 :            : 
     592                 :            : /* pull the slot out of the reader private data */
     593                 :            : static PK11SlotInfo *
     594                 :            : vcard_emul_reader_get_slot(VReader *vreader)
     595                 :            : {
     596                 :         10 :     VReaderEmul *vreader_emul = vreader_get_private(vreader);
     597   [ +  -  -  + ]:         10 :     if (vreader_emul == NULL) {
     598                 :            :         return NULL;
     599                 :            :     }
     600                 :         10 :     return vreader_emul->slot;
     601                 :            : }
     602                 :            : 
     603                 :            : /*
     604                 :            :  *  Card ATR's map to physical cards. vcard_alloc_atr will set appropriate
     605                 :            :  *  historical bytes for any software emulated card. The remaining bytes can be
     606                 :            :  *  used to indicate the actual emulator
     607                 :            :  */
     608                 :            : static unsigned char *nss_atr;
     609                 :            : static int nss_atr_len;
     610                 :            : 
     611                 :            : void
     612                 :          1 : vcard_emul_get_atr(G_GNUC_UNUSED VCard *card, unsigned char *atr, int *atr_len)
     613                 :            : {
     614                 :            :     int len;
     615         [ -  + ]:          1 :     assert(atr != NULL);
     616                 :            : 
     617         [ +  - ]:          1 :     if (nss_atr == NULL) {
     618                 :          1 :         nss_atr = vcard_alloc_atr("NSS", &nss_atr_len);
     619                 :            :     }
     620                 :          1 :     len = MIN(nss_atr_len, *atr_len);
     621                 :          1 :     memcpy(atr, nss_atr, len);
     622                 :          1 :     *atr_len = len;
     623                 :          1 : }
     624                 :            : 
     625                 :            : static SECStatus
     626                 :          6 : vcard_emul_create_serial(VCard *card, unsigned char *data, int len)
     627                 :            : {
     628                 :            :     HASH_HashType hashType;
     629                 :            :     HASHContext *hashContext = NULL;
     630                 :            :     unsigned char digest[32];
     631                 :          6 :     unsigned int digestLen = 0;
     632                 :            : 
     633                 :          6 :     hashType = HASH_GetHashTypeByOidTag(SEC_OID_SHA256);
     634                 :          6 :     hashContext = HASH_Create(hashType);
     635         [ +  - ]:          6 :     if (hashContext == NULL) {
     636                 :            :         return SECFailure;
     637                 :            :     }
     638                 :            : 
     639                 :          6 :     HASH_Begin(hashContext);
     640                 :          6 :     HASH_Update(hashContext, data, len);
     641                 :          6 :     HASH_End(hashContext, digest, &digestLen, 32);
     642                 :          6 :     HASH_Destroy(hashContext);
     643                 :            : 
     644                 :          6 :     vcard_set_serial(card, digest, (size_t) digestLen);
     645                 :            : 
     646                 :          6 :     return SECSuccess;
     647                 :            : }
     648                 :            : 
     649                 :            : /*
     650                 :            :  * create a new card from certs and keys
     651                 :            :  */
     652                 :            : static VCard *
     653                 :          6 : vcard_emul_make_card(VReader *reader,
     654                 :            :                      unsigned char * const *certs, int *cert_len,
     655                 :            :                      VCardKey *keys[], int cert_count)
     656                 :            : {
     657                 :            :     VCardEmul *vcard_emul;
     658                 :            :     VCard *vcard;
     659                 :            :     PK11SlotInfo *slot;
     660                 :            :     VCardEmulType type;
     661                 :            :     const char *params;
     662                 :            : 
     663                 :          6 :     g_debug("%s: called", __func__);
     664                 :            : 
     665                 :          6 :     type = vcard_emul_get_type(reader);
     666                 :            : 
     667                 :            :     /* ignore the inserted card */
     668         [ -  + ]:          6 :     if (type == VCARD_EMUL_NONE) {
     669                 :            :         return NULL;
     670                 :            :     }
     671                 :            :     slot = vcard_emul_reader_get_slot(reader);
     672         [ -  + ]:          6 :     if (slot == NULL) {
     673                 :            :         return NULL;
     674                 :            :     }
     675                 :            : 
     676                 :            :     params = vcard_emul_get_type_params(reader);
     677                 :            :     /* params these can be NULL */
     678                 :            : 
     679                 :            :     vcard_emul = vcard_emul_new_card(slot);
     680                 :            :     if (vcard_emul == NULL) {
     681                 :            :         return NULL;
     682                 :            :     }
     683                 :          6 :     vcard = vcard_new(vcard_emul, vcard_emul_delete_card);
     684         [ -  + ]:          6 :     if (vcard == NULL) {
     685                 :            :         vcard_emul_delete_card(vcard_emul);
     686                 :          0 :         return NULL;
     687                 :            :     }
     688                 :            : 
     689         [ +  - ]:          6 :     if (cert_count > 0) {
     690                 :          6 :         vcard_emul_create_serial(vcard, certs[0], cert_len[0]);
     691                 :            :     }
     692                 :            : 
     693                 :          6 :     vcard_init(reader, vcard, type, params, certs, cert_len, keys, cert_count);
     694                 :          6 :     return vcard;
     695                 :            : }
     696                 :            : 
     697                 :            : 
     698                 :            : /*
     699                 :            :  * 'clone' a physical card as a virtual card
     700                 :            :  */
     701                 :            : static VCard *
     702                 :          4 : vcard_emul_mirror_card(VReader *vreader)
     703                 :            : {
     704                 :            :     /*
     705                 :            :      * lookup certs using the C_FindObjects. The Stan Cert handle won't give
     706                 :            :      * us the real certs until we log in.
     707                 :            :      */
     708                 :            :     PK11GenericObject *firstObj, *thisObj;
     709                 :            :     int cert_count, i;
     710                 :            :     unsigned char **certs;
     711                 :            :     SECItem **ids;
     712                 :            :     int *cert_len;
     713                 :            :     VCardKey **keys;
     714                 :            :     PK11SlotInfo *slot;
     715                 :            :     VCard *card;
     716                 :            : 
     717                 :          4 :     g_debug("%s: called", __func__);
     718                 :            : 
     719                 :            :     slot = vcard_emul_reader_get_slot(vreader);
     720         [ -  + ]:          4 :     if (slot == NULL) {
     721                 :            :         return NULL;
     722                 :            :     }
     723                 :            : 
     724                 :          4 :     firstObj = PK11_FindGenericObjects(slot, CKO_CERTIFICATE);
     725         [ +  + ]:          4 :     if (firstObj == NULL) {
     726                 :            :         return NULL;
     727                 :            :     }
     728                 :            : 
     729                 :            :     /* count the certs */
     730                 :            :     cert_count = 0;
     731         [ +  + ]:          6 :     for (thisObj = firstObj; thisObj;
     732                 :          4 :                              thisObj = PK11_GetNextGenericObject(thisObj)) {
     733                 :          4 :         cert_count++;
     734                 :            :     }
     735                 :            : 
     736                 :            :     /* allocate the arrays */
     737                 :          2 :     vcard_emul_alloc_arrays(&certs, &cert_len, &keys, cert_count);
     738   [ -  +  -  - ]:          2 :     ids = g_new(SECItem *, cert_count);
     739                 :            : 
     740                 :            :     /* fill in the arrays */
     741                 :            :     cert_count = i = 0;
     742         [ +  + ]:          6 :     for (thisObj = firstObj; thisObj;
     743                 :          4 :                              thisObj = PK11_GetNextGenericObject(thisObj)) {
     744                 :            :         SECItem derCert, *id;
     745                 :            :         CERTCertificate *cert;
     746                 :            :         SECStatus rv;
     747                 :            : 
     748                 :          4 :         g_debug("%s: Found certificate", __func__);
     749                 :          4 :         rv = PK11_ReadRawAttribute(PK11_TypeGeneric, thisObj,
     750                 :            :                                    CKA_VALUE, &derCert);
     751         [ -  + ]:          4 :         if (rv != SECSuccess) {
     752                 :          0 :             continue;
     753                 :            :         }
     754                 :            :         /* Read ID and try to sort by this to get reproducible results
     755                 :            :          * in case of underlying pkcs11 module does not provide it */
     756                 :          4 :         id = SECITEM_AllocItem(NULL, NULL, 0);
     757                 :          4 :         rv = PK11_ReadRawAttribute(PK11_TypeGeneric, thisObj, CKA_ID, id);
     758         [ -  + ]:          4 :         if (rv != SECSuccess) {
     759                 :          0 :             SECITEM_FreeItem(&derCert, PR_FALSE);
     760                 :          0 :             SECITEM_FreeItem(id, PR_TRUE);
     761                 :          0 :             continue;
     762                 :            :         }
     763                 :            :         /* create floating temp cert. This gives us a cert structure even if
     764                 :            :          * the token isn't logged in */
     765                 :          4 :         cert = CERT_NewTempCertificate(CERT_GetDefaultCertDB(), &derCert,
     766                 :            :                                        NULL, PR_FALSE, PR_TRUE);
     767                 :          4 :         SECITEM_FreeItem(&derCert, PR_FALSE);
     768         [ -  + ]:          4 :         if (cert == NULL) {
     769                 :          0 :             SECITEM_FreeItem(id, PR_TRUE);
     770                 :          0 :             continue;
     771                 :            :         }
     772                 :            : 
     773         [ +  + ]:          6 :         for (i = 0; i < cert_count; i++) {
     774         [ -  + ]:          2 :             if (SECITEM_CompareItem(id, ids[i]) < SECEqual) {
     775                 :            :                 /* Make space for the item here, move the rest of the items */
     776                 :          0 :                 memmove(&certs[i + 1], &certs[i], (cert_count - i) * sizeof(certs[0]));
     777                 :          0 :                 memmove(&cert_len[i + 1], &cert_len[i], (cert_count - i) * sizeof(cert_len[0]));
     778                 :          0 :                 memmove(&keys[i + 1], &keys[i], (cert_count - i) * sizeof(keys[0]));
     779                 :          0 :                 memmove(&ids[i + 1], &ids[i], (cert_count - i) * sizeof(ids[0]));
     780                 :          0 :                 break;
     781                 :            :             }
     782                 :            :         }
     783                 :          4 :         certs[i] = cert->derCert.data;
     784                 :          4 :         cert_len[i] = cert->derCert.len;
     785                 :          4 :         keys[i] = vcard_emul_make_key(slot, cert);
     786                 :          4 :         ids[i] = id;
     787                 :          4 :         cert_count++;
     788                 :          4 :         CERT_DestroyCertificate(cert); /* key obj still has a reference */
     789                 :            :     }
     790                 :          2 :     PK11_DestroyGenericObjects(firstObj);
     791                 :            :     /* No longer needed */
     792         [ +  + ]:          6 :     for (i = 0; i < cert_count; i++) {
     793                 :          4 :         SECITEM_FreeItem(ids[i], PR_TRUE);
     794                 :            :     }
     795                 :          2 :     g_free(ids);
     796                 :            : 
     797                 :            :     /* now create the card */
     798                 :          2 :     card = vcard_emul_make_card(vreader, certs, cert_len, keys, cert_count);
     799                 :          2 :     g_free(certs);
     800                 :          2 :     g_free(cert_len);
     801                 :          2 :     g_free(keys);
     802                 :            : 
     803                 :          2 :     return card;
     804                 :            : }
     805                 :            : 
     806                 :            : static VCardEmulType default_card_type = VCARD_EMUL_NONE;
     807                 :            : static const char *default_type_params = "";
     808                 :            : 
     809                 :            : /*
     810                 :            :  * This thread looks for card and reader insertions and puts events on the
     811                 :            :  * event queue
     812                 :            :  */
     813                 :            : static void
     814                 :          2 : vcard_emul_event_thread(void *arg)
     815                 :            : {
     816                 :            :     PK11SlotInfo *slot;
     817                 :            :     VReader *vreader;
     818                 :            :     VReaderEmul *vreader_emul;
     819                 :            :     VCard *vcard;
     820                 :            :     SECMODModule *module = (SECMODModule *)arg;
     821                 :            : 
     822                 :            :     do {
     823                 :            :         /*
     824                 :            :          * XXX - the latency value doesn't matter one bit. you only get no
     825                 :            :          * blocking (flags |= CKF_DONT_BLOCK) or PKCS11_WAIT_LATENCY (==500),
     826                 :            :          * hard coded in coolkey.  And it isn't coolkey's fault - the timeout
     827                 :            :          * value we pass get's dropped on the floor before C_WaitForSlotEvent
     828                 :            :          * is called.
     829                 :            :          */
     830                 :          6 :         slot = SECMOD_WaitForAnyTokenEvent(module, 0, 500);
     831         [ -  + ]:          4 :         if (slot == NULL) {
     832                 :            :             /* this could be just a no event indication */
     833         [ #  # ]:          0 :             if (PORT_GetError() == SEC_ERROR_NO_EVENT) {
     834                 :          0 :                 continue;
     835                 :            :             }
     836                 :            :             break;
     837                 :            :         }
     838                 :          4 :         vreader = vcard_emul_find_vreader_from_slot(slot);
     839         [ -  + ]:          4 :         if (vreader == NULL) {
     840                 :            :             /* new vreader */
     841                 :          0 :             vreader_emul = vreader_emul_new(slot, default_card_type,
     842                 :            :                                             default_type_params);
     843                 :          0 :             vreader = vreader_new(PK11_GetSlotName(slot), vreader_emul,
     844                 :            :                                   vreader_emul_delete);
     845                 :          0 :             PK11_FreeSlot(slot);
     846                 :            :             slot = NULL;
     847                 :          0 :             vreader_add_reader(vreader);
     848                 :          0 :             vreader_free(vreader);
     849                 :          0 :             continue;
     850                 :            :         }
     851                 :            :         /* card remove/insert */
     852                 :          4 :         vreader_emul = vreader_get_private(vreader);
     853         [ +  - ]:          4 :         if (PK11_IsPresent(slot)) {
     854                 :          4 :             int series = PK11_GetSlotSeries(slot);
     855         [ -  + ]:          4 :             if (series != vreader_emul->series) {
     856         [ #  # ]:          0 :                 if (vreader_emul->present) {
     857                 :          0 :                     vreader_insert_card(vreader, NULL);
     858                 :            :                 }
     859                 :          0 :                 vcard = vcard_emul_mirror_card(vreader);
     860                 :          0 :                 vreader_insert_card(vreader, vcard);
     861                 :          0 :                 vcard_free(vcard);
     862                 :            :             }
     863                 :          4 :             vreader_emul->series = series;
     864                 :          4 :             vreader_emul->present = 1;
     865                 :          4 :             vreader_free(vreader);
     866                 :          4 :             PK11_FreeSlot(slot);
     867                 :          4 :             continue;
     868                 :            :         }
     869         [ #  # ]:          0 :         if (vreader_emul->present) {
     870                 :          0 :             vreader_insert_card(vreader, NULL);
     871                 :            :         }
     872                 :          0 :         vreader_emul->series = 0;
     873                 :          0 :         vreader_emul->present = 0;
     874                 :          0 :         PK11_FreeSlot(slot);
     875                 :          0 :         vreader_free(vreader);
     876                 :            :     } while (1);
     877                 :          0 : }
     878                 :            : 
     879                 :            : /* if the card is inserted when we start up, make sure our state is correct */
     880                 :            : static void
     881                 :          8 : vcard_emul_init_series(VReader *vreader, G_GNUC_UNUSED VCard *vcard)
     882                 :            : {
     883                 :          8 :     VReaderEmul *vreader_emul = vreader_get_private(vreader);
     884                 :          8 :     PK11SlotInfo *slot = vreader_emul->slot;
     885                 :            : 
     886                 :          8 :     vreader_emul->present = PK11_IsPresent(slot);
     887                 :          8 :     vreader_emul->series = PK11_GetSlotSeries(slot);
     888         [ -  + ]:          8 :     if (vreader_emul->present == 0) {
     889                 :          0 :         vreader_insert_card(vreader, NULL);
     890                 :            :     }
     891                 :          8 : }
     892                 :            : 
     893                 :            : /*
     894                 :            :  * each module has a separate wait call, create a thread for each module that
     895                 :            :  * we are using.
     896                 :            :  */
     897                 :            : static void
     898                 :            : vcard_emul_new_event_thread(SECMODModule *module)
     899                 :            : {
     900                 :          2 :     PR_CreateThread(PR_SYSTEM_THREAD, vcard_emul_event_thread,
     901                 :            :                      module, PR_PRIORITY_HIGH, PR_GLOBAL_THREAD,
     902                 :            :                      PR_UNJOINABLE_THREAD, 0);
     903                 :          2 : }
     904                 :            : 
     905                 :            : static const VCardEmulOptions default_options = {
     906                 :            :     .nss_db = NULL,
     907                 :            :     .vreader = NULL,
     908                 :            :     .vreader_count = 0,
     909                 :            :     .hw_card_type = VCARD_EMUL_CAC,
     910                 :            :     .hw_type_params = NULL,
     911                 :            :     .use_hw = USE_HW_YES,
     912                 :            : };
     913                 :            : 
     914                 :            : 
     915                 :            : /*
     916                 :            :  *  NSS needs the app to supply a password prompt. In our case the only time
     917                 :            :  *  the password is supplied is as part of the Login APDU. The actual password
     918                 :            :  *  is passed in the pw_arg in that case. In all other cases pw_arg should be
     919                 :            :  *  NULL.
     920                 :            :  */
     921                 :            : static char *
     922                 :         16 : vcard_emul_get_password(G_GNUC_UNUSED PK11SlotInfo *slot, PRBool retries, void *pw_arg)
     923                 :            : {
     924                 :            :     /* if it didn't work the first time, don't keep trying */
     925         [ +  - ]:         16 :     if (retries) {
     926                 :            :         return NULL;
     927                 :            :     }
     928                 :            :     /* we are looking up a password when we don't have one in hand */
     929         [ +  - ]:         16 :     if (pw_arg == NULL) {
     930                 :            :         return NULL;
     931                 :            :     }
     932                 :            :     /* TODO: we really should verify that were are using the right slot */
     933                 :         16 :     return PORT_Strdup(pw_arg);
     934                 :            : }
     935                 :            : 
     936                 :            : /* Force a card removal even if the card is not physically removed */
     937                 :            : VCardEmulError
     938                 :          2 : vcard_emul_force_card_remove(VReader *vreader)
     939                 :            : {
     940   [ +  -  +  + ]:          2 :     if (!nss_emul_init || (vreader_card_is_present(vreader) != VREADER_OK)) {
     941                 :          1 :         return VCARD_EMUL_FAIL; /* card is already removed */
     942                 :            :     }
     943                 :            : 
     944                 :            :     /* OK, remove it */
     945                 :          1 :     vreader_insert_card(vreader, NULL);
     946                 :          1 :     return VCARD_EMUL_OK;
     947                 :            : }
     948                 :            : 
     949                 :            : /* Re-insert of a card that has been removed by force removal */
     950                 :            : VCardEmulError
     951                 :          2 : vcard_emul_force_card_insert(VReader *vreader)
     952                 :            : {
     953                 :            :     VReaderEmul *vreader_emul;
     954                 :            :     VCard *vcard;
     955                 :            : 
     956   [ +  -  +  + ]:          2 :     if (!nss_emul_init || (vreader_card_is_present(vreader) == VREADER_OK)) {
     957                 :          1 :         return VCARD_EMUL_FAIL; /* card is already removed */
     958                 :            :     }
     959                 :          1 :     vreader_emul = vreader_get_private(vreader);
     960                 :            : 
     961                 :            :     /* if it's a softcard, get the saved vcard from the reader emul structure */
     962         [ +  - ]:          1 :     if (vreader_emul->saved_vcard) {
     963                 :          1 :         vcard = vcard_reference(vreader_emul->saved_vcard);
     964                 :            :     } else {
     965                 :            :         /* it must be a physical card, rebuild it */
     966         [ #  # ]:          0 :         if (!PK11_IsPresent(vreader_emul->slot)) {
     967                 :            :             /* physical card has been removed, not way to reinsert it */
     968                 :            :             return VCARD_EMUL_FAIL;
     969                 :            :         }
     970                 :          0 :         vcard = vcard_emul_mirror_card(vreader);
     971                 :            :     }
     972                 :          1 :     vreader_insert_card(vreader, vcard);
     973                 :          1 :     vcard_free(vcard);
     974                 :            : 
     975                 :          1 :     return VCARD_EMUL_OK;
     976                 :            : }
     977                 :            : 
     978                 :            : /* Previously we returned FAIL if no readers found. This makes
     979                 :            :  * no sense when using hardware, since there may be no readers connected
     980                 :            :  * at the time vcard_emul_init is called, but they will be properly
     981                 :            :  * recognized later. So Instead return FAIL only if no_hw==1 and no
     982                 :            :  * vcards can be created (indicates error with certificates provided
     983                 :            :  * or db), or if any other higher level error (NSS error, missing coolkey). */
     984                 :            : static int vcard_emul_init_called;
     985                 :            : static NSSInitContext *nss_ctx = NULL;
     986                 :            : 
     987                 :            : VCardEmulError
     988                 :          8 : vcard_emul_init(const VCardEmulOptions *options)
     989                 :            : {
     990                 :            :     PRBool has_readers = PR_FALSE;
     991                 :            :     VReader *vreader;
     992                 :            :     VReaderEmul *vreader_emul;
     993                 :            :     SECMODListLock *module_lock;
     994                 :            :     SECMODModuleList *module_list;
     995                 :            :     SECMODModuleList *mlp;
     996                 :            :     int i;
     997                 :            :     gchar *path = NULL;
     998                 :            :     const gchar *nss_db;
     999                 :            : 
    1000                 :          8 :     g_debug("%s: called", __func__);
    1001                 :            : 
    1002         [ +  + ]:          8 :     if (vcard_emul_init_called) {
    1003                 :            :         return VCARD_EMUL_INIT_ALREADY_INITED;
    1004                 :            :     }
    1005                 :          7 :     vcard_emul_init_called = 1;
    1006                 :          7 :     vreader_init();
    1007                 :          7 :     vevent_queue_init();
    1008                 :            : 
    1009         [ -  + ]:          7 :     if (options == NULL) {
    1010                 :            :         options = &default_options;
    1011                 :            :     }
    1012                 :            : 
    1013                 :            : #if defined(ENABLE_PCSC)
    1014                 :            :     if (options->use_hw && options->hw_card_type == VCARD_EMUL_PASSTHRU) {
    1015                 :            :         if (options->vreader_count > 0) {
    1016                 :            :             fprintf(stderr, "Error: you cannot use a soft card and "
    1017                 :            :                             "a passthru card simultaneously.\n");
    1018                 :            :             return VCARD_EMUL_FAIL;
    1019                 :            :         }
    1020                 :            : 
    1021                 :            :         if (capcsc_init()) {
    1022                 :            :             fprintf(stderr, "Error initializing PCSC interface.\n");
    1023                 :            :             return VCARD_EMUL_FAIL;
    1024                 :            :         }
    1025                 :            : 
    1026                 :            :         g_debug("%s: returning with passthrough initialized", __func__);
    1027                 :            :         return VCARD_EMUL_OK;
    1028                 :            :     }
    1029                 :            : #endif
    1030                 :            : 
    1031                 :            :     /* first initialize NSS */
    1032                 :          7 :     nss_db = options->nss_db;
    1033         [ -  + ]:          7 :     if (nss_db == NULL) {
    1034                 :            : #ifndef _WIN32
    1035                 :            :         nss_db = "/etc/pki/nssdb";
    1036                 :            : #else
    1037                 :            :         const gchar * const *config_dirs = g_get_system_config_dirs();
    1038                 :            :         if (config_dirs == NULL || config_dirs[0] == NULL) {
    1039                 :            :             return VCARD_EMUL_FAIL;
    1040                 :            :         }
    1041                 :            : 
    1042                 :            :         path = g_build_filename(config_dirs[0], "pki", "nssdb", NULL);
    1043                 :            :         nss_db = path;
    1044                 :            : #endif
    1045                 :            :     }
    1046                 :            : 
    1047                 :          7 :     nss_ctx = NSS_InitContext(nss_db, "", "", "", NULL, NSS_INIT_READONLY);
    1048         [ +  + ]:          7 :     if (nss_ctx == NULL) {
    1049                 :          1 :         g_debug("%s: NSS_InitContext failed. Does the DB directory '%s' exist?",
    1050                 :            :                 __func__, nss_db);
    1051                 :          1 :         g_free(path);
    1052                 :          1 :         return VCARD_EMUL_FAIL;
    1053                 :            :     }
    1054                 :          6 :     g_free(path);
    1055                 :            :     path = NULL;
    1056                 :            : 
    1057                 :            :     /* Set password callback function */
    1058                 :          6 :     PK11_SetPasswordFunc(vcard_emul_get_password);
    1059                 :            : 
    1060                 :            :     /* set up soft cards emulated by software certs rather than physical cards
    1061                 :            :      * */
    1062         [ +  + ]:         10 :     for (i = 0; i < options->vreader_count; i++) {
    1063                 :            :         int j;
    1064                 :            :         int cert_count;
    1065                 :            :         unsigned char **certs;
    1066                 :            :         int *cert_len;
    1067                 :            :         VCardKey **keys;
    1068                 :            :         PK11SlotInfo *slot;
    1069                 :            : 
    1070                 :          4 :         slot = PK11_FindSlotByName(options->vreader[i].name);
    1071         [ -  + ]:          4 :         if (slot == NULL) {
    1072                 :          0 :             continue;
    1073                 :            :         }
    1074                 :          4 :         vreader_emul = vreader_emul_new(slot, options->vreader[i].card_type,
    1075                 :          4 :                                         options->vreader[i].type_params);
    1076                 :          4 :         vreader = vreader_new(options->vreader[i].vname, vreader_emul,
    1077                 :            :                               vreader_emul_delete);
    1078                 :          4 :         vreader_add_reader(vreader);
    1079                 :            : 
    1080                 :          4 :         vcard_emul_alloc_arrays(&certs, &cert_len, &keys,
    1081                 :          4 :                                 options->vreader[i].cert_count);
    1082                 :            : 
    1083                 :            :         cert_count = 0;
    1084         [ +  + ]:         16 :         for (j = 0; j < options->vreader[i].cert_count; j++) {
    1085                 :            :             /* we should have a better way of identifying certs than by
    1086                 :            :              * nickname here */
    1087                 :         12 :             CERTCertificate *cert = PK11_FindCertFromNickname(
    1088                 :         12 :                                         options->vreader[i].cert_name[j],
    1089                 :            :                                         NULL);
    1090         [ -  + ]:         12 :             if (cert == NULL) {
    1091                 :          0 :                 continue;
    1092                 :            :             }
    1093                 :         12 :             certs[cert_count] = cert->derCert.data;
    1094                 :         12 :             cert_len[cert_count] = cert->derCert.len;
    1095                 :         12 :             keys[cert_count] = vcard_emul_make_key(slot, cert);
    1096                 :            :             /* this is safe because the key is still holding a cert reference */
    1097                 :         12 :             CERT_DestroyCertificate(cert);
    1098                 :         12 :             cert_count++;
    1099                 :            :         }
    1100         [ +  - ]:          4 :         if (cert_count) {
    1101                 :          4 :             VCard *vcard = vcard_emul_make_card(vreader, certs, cert_len,
    1102                 :            :                                                 keys, cert_count);
    1103                 :          4 :             vreader_insert_card(vreader, vcard);
    1104                 :          4 :             vcard_emul_init_series(vreader, vcard);
    1105                 :            :             /* allow insertion and removal of soft cards */
    1106                 :          4 :             vreader_emul->saved_vcard = vcard_reference(vcard);
    1107                 :          4 :             vcard_free(vcard);
    1108                 :          4 :             vreader_free(vreader);
    1109                 :            :             has_readers = PR_TRUE;
    1110                 :            :         }
    1111                 :          4 :         PK11_FreeSlot(slot);
    1112                 :          4 :         g_free(certs);
    1113                 :          4 :         g_free(cert_len);
    1114                 :          4 :         g_free(keys);
    1115                 :            :     }
    1116                 :            : 
    1117                 :            :     /* if we aren't suppose to use hw, skip looking up hardware tokens */
    1118         [ +  + ]:          6 :     if (!options->use_hw) {
    1119                 :          4 :         nss_emul_init = has_readers;
    1120                 :          4 :         g_debug("%s: returning: Not using HW", __func__);
    1121                 :          4 :         return has_readers ? VCARD_EMUL_OK : VCARD_EMUL_FAIL;
    1122                 :            :     }
    1123                 :            : 
    1124                 :            :     /* make sure we have some PKCS #11 module loaded */
    1125                 :          2 :     module_lock = SECMOD_GetDefaultModuleListLock();
    1126                 :          2 :     module_list = SECMOD_GetDefaultModuleList();
    1127                 :            : 
    1128                 :            :     /* now examine all the slots, finding which should be readers */
    1129                 :            :     /* We should control this with options. For now we mirror out any
    1130                 :            :      * removable hardware slot */
    1131                 :          2 :     default_card_type = options->hw_card_type;
    1132                 :          2 :     default_type_params = g_strdup(options->hw_type_params);
    1133                 :            : 
    1134                 :          2 :     SECMOD_GetReadLock(module_lock);
    1135         [ +  + ]:          6 :     for (mlp = module_list; mlp; mlp = mlp->next) {
    1136                 :          4 :         SECMODModule *module = mlp->module;
    1137                 :            : 
    1138                 :            :         /* Ignore the internal module */
    1139   [ +  -  +  + ]:          4 :         if (module == NULL || module == SECMOD_GetInternalModule()) {
    1140                 :          2 :             continue;
    1141                 :            :         }
    1142                 :            : 
    1143                 :          2 :         g_debug("%s: Listing modules, trying %s", __func__, module->commonName);
    1144         [ +  + ]:          6 :         for (i = 0; i < module->slotCount; i++) {
    1145                 :          4 :             PK11SlotInfo *slot = module->slots[i];
    1146                 :            : 
    1147                 :            :             /* only map removable HW slots */
    1148   [ +  -  +  - ]:          4 :             if (slot == NULL || !PK11_IsRemovable(slot) ||
    1149   [ -  +  -  - ]:          4 :                 (options->use_hw == USE_HW_YES && !PK11_IsHW(slot))) {
    1150                 :          0 :                 continue;
    1151                 :            :             }
    1152         [ -  + ]:          4 :             if (strcmp("E-Gate 0 0", PK11_GetSlotName(slot)) == 0) {
    1153                 :            :                 /*
    1154                 :            :                  * coolkey <= 1.1.0-20 emulates this reader if it can't find
    1155                 :            :                  * any hardware readers. This causes problems, warn user of
    1156                 :            :                  * problems.
    1157                 :            :                  */
    1158                 :          0 :                 fprintf(stderr, "known bad coolkey version - see "
    1159                 :            :                         "https://bugzilla.redhat.com/show_bug.cgi?id=802435\n");
    1160                 :          0 :                 continue;
    1161                 :            :             }
    1162                 :          4 :             vreader_emul = vreader_emul_new(slot, options->hw_card_type,
    1163                 :          4 :                                             options->hw_type_params);
    1164                 :          4 :             vreader = vreader_new(PK11_GetSlotName(slot), vreader_emul,
    1165                 :            :                                   vreader_emul_delete);
    1166                 :          4 :             vreader_add_reader(vreader);
    1167                 :          4 :             g_debug("%s: Added reader from slot %s", __func__,
    1168                 :            :                     PK11_GetSlotName(slot));
    1169                 :            : 
    1170         [ +  - ]:          4 :             if (PK11_IsPresent(slot)) {
    1171                 :            :                 VCard *vcard;
    1172                 :          4 :                 vcard = vcard_emul_mirror_card(vreader);
    1173                 :          4 :                 vreader_insert_card(vreader, vcard);
    1174                 :          4 :                 vcard_emul_init_series(vreader, vcard);
    1175                 :          4 :                 g_debug("%s: Added card to the reader %s", __func__,
    1176                 :            :                         vreader_get_name(vreader));
    1177                 :          4 :                 vcard_free(vcard);
    1178                 :            :             }
    1179                 :          4 :             vreader_free(vreader);
    1180                 :            :         }
    1181                 :            :         vcard_emul_new_event_thread(module);
    1182                 :            :     }
    1183                 :          2 :     SECMOD_ReleaseReadLock(module_lock);
    1184                 :          2 :     nss_emul_init = PR_TRUE;
    1185                 :            : 
    1186                 :          2 :     return VCARD_EMUL_OK;
    1187                 :            : }
    1188                 :            : 
    1189                 :            : /* Recreate card insert events for all readers (user should
    1190                 :            :  * deduce implied reader insert. perhaps do a reader insert as well?)
    1191                 :            :  */
    1192                 :            : void
    1193                 :          0 : vcard_emul_replay_insertion_events(void)
    1194                 :            : {
    1195                 :            :     VReaderListEntry *current_entry;
    1196                 :            :     VReaderListEntry *next_entry;
    1197                 :          0 :     VReaderList *list = vreader_get_reader_list();
    1198                 :            : 
    1199         [ #  # ]:          0 :     for (current_entry = vreader_list_get_first(list); current_entry;
    1200                 :            :             current_entry = next_entry) {
    1201                 :          0 :         VReader *vreader = vreader_list_get_reader(current_entry);
    1202                 :          0 :         next_entry = vreader_list_get_next(current_entry);
    1203                 :          0 :         vreader_queue_card_event(vreader);
    1204                 :            :     }
    1205                 :            : 
    1206                 :          0 :     vreader_list_delete(list);
    1207                 :          0 : }
    1208                 :            : 
    1209                 :            : VCardEmulError
    1210                 :          5 : vcard_emul_finalize(void)
    1211                 :            : {
    1212                 :            :     SECStatus rv;
    1213                 :            : 
    1214                 :          5 :     rv = NSS_ShutdownContext(nss_ctx);
    1215         [ +  + ]:          5 :     if (rv != SECSuccess) {
    1216                 :          2 :         g_debug("%s: NSS_ShutdownContext failed.", __func__);
    1217                 :          2 :         return VCARD_EMUL_FAIL;
    1218                 :            :     }
    1219                 :          3 :     nss_ctx = NULL;
    1220                 :            : 
    1221                 :          3 :     return VCARD_EMUL_OK;
    1222                 :            : }
    1223                 :            : 
    1224                 :            : /*
    1225                 :            :  *  Silly little functions to help parsing our argument string
    1226                 :            :  */
    1227                 :            : static int
    1228                 :            : count_tokens(const char *str, char token, char token_end)
    1229                 :            : {
    1230                 :            :     int count = 0;
    1231                 :            : 
    1232         [ +  - ]:         90 :     for (; *str; str++) {
    1233         [ +  + ]:         90 :         if (*str == token) {
    1234                 :         10 :             count++;
    1235                 :            :         }
    1236         [ +  + ]:         90 :         if (*str == token_end) {
    1237                 :            :             break;
    1238                 :            :         }
    1239                 :            :     }
    1240                 :            :     return count;
    1241                 :            : }
    1242                 :            : 
    1243                 :            : static const char *
    1244                 :         83 : strip(const char *str)
    1245                 :            : {
    1246   [ +  +  +  + ]:         97 :     for (; *str && isspace(*str); str++) {
    1247                 :            :     }
    1248                 :         83 :     return str;
    1249                 :            : }
    1250                 :            : 
    1251                 :            : static const char *
    1252                 :          8 : find_blank(const char *str)
    1253                 :            : {
    1254   [ +  +  +  + ]:         45 :     for (; *str && !isspace(*str); str++) {
    1255                 :            :     }
    1256                 :          8 :     return str;
    1257                 :            : }
    1258                 :            : 
    1259                 :            : 
    1260                 :            : /*
    1261                 :            :  *  We really want to use some existing argument parsing library here. That
    1262                 :            :  *  would give us a consistent look */
    1263                 :            : static VCardEmulOptions options;
    1264                 :            : #define READER_STEP 4
    1265                 :            : 
    1266                 :            : /* Expects "args" to be at the beginning of a token (ie right after the ','
    1267                 :            :  * ending the previous token), and puts the next token start in "token",
    1268                 :            :  * and its length in "token_length". "token" will not be nul-terminated.
    1269                 :            :  * After calling the macro, "args" will be advanced to the beginning of
    1270                 :            :  * the next token.
    1271                 :            :  */
    1272                 :            : #define NEXT_TOKEN(token) \
    1273                 :            :             (token) = args; \
    1274                 :            :             args = strpbrk(args, ",)"); \
    1275                 :            :             if (args == NULL || *args == 0 || *args == ')') { \
    1276                 :            :                 fprintf(stderr, "Error: invalid soft specification.\n"); \
    1277                 :            :                 goto fail; \
    1278                 :            :             } \
    1279                 :            :             (token##_length) = args - (token); \
    1280                 :            :             args = strip(args+1);
    1281                 :            : 
    1282                 :            : VCardEmulOptions *
    1283                 :          8 : vcard_emul_options(const char *args)
    1284                 :            : {
    1285                 :            :     int i, j, reader_count = 0;
    1286                 :            :     VCardEmulOptions *opts;
    1287                 :            : 
    1288                 :            :     /* Allow the future use of allocating the options structure on the fly */
    1289                 :          8 :     memcpy(&options, &default_options, sizeof(options));
    1290                 :            :     opts = &options;
    1291                 :            : 
    1292                 :            :     do {
    1293                 :         22 :         args = strip(args); /* strip off the leading spaces */
    1294         [ -  + ]:         22 :         if (*args == ',') {
    1295                 :          0 :             args++;
    1296                 :          0 :             continue;
    1297                 :            :         }
    1298                 :            :         /* soft=(slot_name,virt_name,emul_type,emul_flags,cert_1, (no eol)
    1299                 :            :          *       cert_2,cert_3...) */
    1300         [ +  + ]:         22 :         if (strncmp(args, "soft=", 5) == 0) {
    1301                 :            :             const char *name;
    1302                 :            :             size_t name_length;
    1303                 :            :             const char *vname;
    1304                 :            :             size_t vname_length;
    1305                 :            :             const char *type_params;
    1306                 :            :             size_t type_params_length;
    1307                 :            :             char type_str[100];
    1308                 :            :             VCardEmulType type;
    1309                 :            :             int count;
    1310                 :            :             VirtualReaderOptions *vreaderOpt;
    1311                 :            : 
    1312                 :          5 :             args = strip(args + 5);
    1313         [ -  + ]:          5 :             if (*args != '(') {
    1314                 :          0 :                 fprintf(stderr, "Error: invalid soft specification.\n");
    1315                 :          0 :                 goto fail;
    1316                 :            :             }
    1317                 :          5 :             args = strip(args+1);
    1318                 :            : 
    1319   [ +  -  +  -  :          5 :             NEXT_TOKEN(name)
                   -  + ]
    1320   [ +  -  +  -  :          5 :             NEXT_TOKEN(vname)
                   -  + ]
    1321   [ +  -  +  -  :          5 :             NEXT_TOKEN(type_params)
                   -  + ]
    1322                 :          5 :             type_params_length = MIN(type_params_length, sizeof(type_str)-1);
    1323                 :          5 :             memcpy(type_str, type_params, type_params_length);
    1324                 :          5 :             type_str[type_params_length] = '\0';
    1325                 :          5 :             type = vcard_emul_type_from_string(type_str);
    1326         [ -  + ]:          5 :             if (type == VCARD_EMUL_NONE) {
    1327                 :          0 :                 fprintf(stderr, "Error: invalid smartcard type '%s'.\n",
    1328                 :            :                         type_str);
    1329                 :          0 :                 goto fail;
    1330                 :            :             }
    1331                 :            : 
    1332   [ +  -  +  -  :          5 :             NEXT_TOKEN(type_params)
                   -  + ]
    1333                 :            : 
    1334         [ -  + ]:          5 :             if (*args == 0) {
    1335                 :          0 :                 fprintf(stderr, "Error: missing cert specification.\n");
    1336                 :          0 :                 goto fail;
    1337                 :            :             }
    1338                 :            : 
    1339         [ +  - ]:          5 :             if (opts->vreader_count >= reader_count) {
    1340                 :          5 :                 reader_count += READER_STEP;
    1341   [ -  +  -  - ]:          5 :                 opts->vreader = g_renew(VirtualReaderOptions, opts->vreader,
    1342                 :            :                                         reader_count);
    1343                 :            :             }
    1344                 :          5 :             vreaderOpt = &opts->vreader[opts->vreader_count];
    1345                 :          5 :             vreaderOpt->name = g_strndup(name, name_length);
    1346                 :          5 :             vreaderOpt->vname = g_strndup(vname, vname_length);
    1347                 :          5 :             vreaderOpt->card_type = type;
    1348                 :          5 :             vreaderOpt->type_params =
    1349                 :          5 :                 g_strndup(type_params, type_params_length);
    1350                 :          5 :             count = count_tokens(args, ',', ')') + 1;
    1351                 :          5 :             vreaderOpt->cert_count = count;
    1352   [ -  +  -  - ]:          5 :             vreaderOpt->cert_name = g_new(char *, count);
    1353         [ +  + ]:         20 :             for (i = 0; i < count; i++) {
    1354                 :            :                 const char *cert = args;
    1355                 :         15 :                 args = strpbrk(args, ",)");
    1356                 :         15 :                 vreaderOpt->cert_name[i] = g_strndup(cert, args - cert);
    1357                 :         15 :                 args = strip(args+1);
    1358                 :            :             }
    1359         [ -  + ]:          5 :             if (*args == ')') {
    1360                 :          0 :                 args++;
    1361                 :            :             }
    1362                 :          5 :             opts->vreader_count++;
    1363                 :            :         /* use_hw= */
    1364         [ +  + ]:         17 :         } else if (strncmp(args, "use_hw=", 7) == 0) {
    1365                 :          8 :             args = strip(args+7);
    1366   [ +  -  +  +  :          8 :             if (*args == '0' || *args == 'N' || *args == 'n' || *args == 'F') {
                   -  + ]
    1367                 :          5 :                 opts->use_hw = USE_HW_NO;
    1368         [ +  - ]:          3 :             } else if (strncmp(args, "removable", 9) == 0) {
    1369                 :          3 :                 opts->use_hw = USE_HW_REMOVABLE;
    1370                 :            :             } else {
    1371                 :          0 :                 opts->use_hw = USE_HW_YES;
    1372                 :            :             }
    1373                 :          8 :             args = find_blank(args);
    1374                 :            :         /* hw_type= */
    1375         [ -  + ]:          9 :         } else if (strncmp(args, "hw_type=", 8) == 0) {
    1376                 :          0 :             args = strip(args+8);
    1377                 :          0 :             opts->hw_card_type = vcard_emul_type_from_string(args);
    1378         [ #  # ]:          0 :             if (opts->hw_card_type == VCARD_EMUL_NONE) {
    1379                 :          0 :                 fprintf(stderr, "Error: invalid smartcard type '%s'.\n",
    1380                 :            :                         args);
    1381                 :          0 :                 goto fail;
    1382                 :            :             }
    1383                 :          0 :             args = find_blank(args);
    1384                 :            :         /* hw_params= */
    1385         [ -  + ]:          9 :         } else if (strncmp(args, "hw_params=", 10) == 0) {
    1386                 :            :             const char *params;
    1387                 :            : 
    1388         [ #  # ]:          0 :             if (opts->hw_type_params != NULL) {
    1389                 :          0 :                 fprintf(stderr, "Error: redefinition of hw_params= is not allowed.\n");
    1390                 :          0 :                 goto fail;
    1391                 :            :             }
    1392                 :          0 :             args = strip(args+10);
    1393                 :            :             params = args;
    1394                 :          0 :             args = find_blank(args);
    1395                 :          0 :             opts->hw_type_params = g_strndup(params, args-params);
    1396                 :            :         /* db="/data/base/path" */
    1397         [ +  + ]:          9 :         } else if (strncmp(args, "db=", 3) == 0) {
    1398                 :            :             const char *db;
    1399                 :            : 
    1400         [ -  + ]:          8 :             if (opts->nss_db != NULL) {
    1401                 :          0 :                 fprintf(stderr, "Error: redefinition of db= is not allowed.\n");
    1402                 :          0 :                 goto fail;
    1403                 :            :             }
    1404                 :          8 :             args = strip(args+3);
    1405         [ -  + ]:          8 :             if (*args != '"') {
    1406                 :          0 :                 fprintf(stderr, "Error: you must quote the file path.\n");
    1407                 :          0 :                 goto fail;
    1408                 :            :             }
    1409                 :          8 :             args++;
    1410                 :            :             db = args;
    1411                 :          8 :             args = strpbrk(args, "\"\n");
    1412         [ -  + ]:          8 :             if (args == NULL) {
    1413                 :          0 :                 fprintf(stderr, "Error: invalid db argument.\n");
    1414                 :          0 :                 goto fail;
    1415                 :            :             }
    1416                 :          8 :             opts->nss_db = g_strndup(db, args-db);
    1417         [ +  - ]:          8 :             if (*args != 0) {
    1418                 :          8 :                 args++;
    1419                 :            :             }
    1420         [ -  + ]:          1 :         } else if (strncmp(args, "nssemul", 7) == 0) {
    1421                 :          0 :             opts->hw_card_type = VCARD_EMUL_CAC;
    1422                 :          0 :             opts->use_hw = USE_HW_YES;
    1423                 :          0 :             args = find_blank(args + 7);
    1424                 :            : #if defined(ENABLE_PCSC)
    1425                 :            :         } else if (strncmp(args, "passthru", 8) == 0) {
    1426                 :            :             opts->hw_card_type = VCARD_EMUL_PASSTHRU;
    1427                 :            :             opts->use_hw = USE_HW_YES;
    1428                 :            :             args = find_blank(args + 8);
    1429                 :            : #endif
    1430                 :            :         } else {
    1431                 :          1 :             fprintf(stderr, "Error: Unknown smartcard specification.\n");
    1432                 :          1 :             goto fail;
    1433                 :            :         }
    1434         [ +  + ]:         21 :     } while (*args != 0);
    1435                 :            : 
    1436                 :            :     return opts;
    1437                 :            : 
    1438                 :            : fail:
    1439                 :            :     /* Clean up what was allocated above on failure */
    1440         [ -  + ]:          1 :     for (i = 0; i < opts->vreader_count; i++) {
    1441                 :          0 :         g_free(opts->vreader[i].name);
    1442                 :          0 :         g_free(opts->vreader[i].vname);
    1443                 :          0 :         g_free(opts->vreader[i].type_params);
    1444         [ #  # ]:          0 :         for (j = 0; j < opts->vreader[i].cert_count; j++) {
    1445                 :          0 :             g_free(opts->vreader[i].cert_name[j]);
    1446                 :            :         }
    1447                 :          0 :         g_free(opts->vreader[i].cert_name);
    1448                 :            :     }
    1449                 :          1 :     g_free(opts->vreader);
    1450                 :          1 :     g_free(opts->hw_type_params);
    1451                 :          1 :     g_free(opts->nss_db);
    1452                 :          1 :     return NULL;
    1453                 :            : }
    1454                 :            : 
    1455                 :            : unsigned char *
    1456                 :          6 : vcard_emul_read_object(VCard *card, const char *label,
    1457                 :            :     unsigned int *ret_len)
    1458                 :            : {
    1459                 :            :     PK11SlotInfo *slot;
    1460                 :            :     PK11GenericObject *obj, *firstObj, *myObj = NULL;
    1461                 :            :     SECItem result;
    1462                 :            :     SECStatus r;
    1463                 :            :     unsigned char *ret;
    1464                 :            : 
    1465                 :            :     slot = vcard_emul_card_get_slot(card);
    1466                 :            : 
    1467                 :          6 :     firstObj = PK11_FindGenericObjects(slot, CKO_DATA);
    1468                 :          6 :     g_debug("%s: Search for generic objects: got %p", __func__, firstObj);
    1469         [ -  + ]:          6 :     for (obj = firstObj; obj; obj = PK11_GetNextGenericObject(obj)) {
    1470                 :            :         int found = 0;
    1471                 :          0 :         r = PK11_ReadRawAttribute(PK11_TypeGeneric, obj,
    1472                 :            :             CKA_LABEL, &result);
    1473         [ #  # ]:          0 :         if (r != SECSuccess) {
    1474                 :          0 :             PK11_DestroyGenericObjects(firstObj);
    1475                 :          0 :             return NULL;
    1476                 :            :         }
    1477                 :            : 
    1478         [ #  # ]:          0 :         if (strlen(label) == result.len
    1479         [ #  # ]:          0 :             && memcmp(label, result.data, result.len) == 0)
    1480                 :            :             found = 1;
    1481                 :            : 
    1482                 :          0 :         PORT_Free(result.data);
    1483                 :          0 :         result.data = NULL;
    1484                 :            : 
    1485         [ #  # ]:          0 :         if (found) {
    1486                 :          0 :             PK11_UnlinkGenericObject(obj);
    1487                 :            :             myObj = obj;
    1488                 :          0 :             break;
    1489                 :            :         }
    1490                 :            :     }
    1491                 :          6 :     PK11_DestroyGenericObjects(firstObj);
    1492                 :            : 
    1493         [ +  - ]:          6 :     if (!myObj)
    1494                 :            :         return NULL;
    1495                 :            : 
    1496                 :          0 :     r = PK11_ReadRawAttribute(PK11_TypeGeneric, myObj,
    1497                 :            :         CKA_VALUE, &result);
    1498                 :          0 :     PK11_DestroyGenericObject(myObj);
    1499         [ #  # ]:          0 :     if (r != SECSuccess)
    1500                 :            :         return NULL;
    1501                 :            : 
    1502                 :          0 :     *ret_len = result.len;
    1503                 :          0 :     ret = g_memdup2(result.data, result.len);
    1504                 :          0 :     PORT_Free(result.data);
    1505                 :          0 :     return ret;
    1506                 :            : }
    1507                 :            : 
    1508                 :            : void
    1509                 :          0 : vcard_emul_usage(void)
    1510                 :            : {
    1511                 :          0 :    fprintf(stderr,
    1512                 :            : "emul args: comma separated list of the following arguments\n"
    1513                 :            : " db={nss_database}               (default sql:/etc/pki/nssdb)\n"
    1514                 :            : " use_hw=[yes|no|removable]       (default yes)\n"
    1515                 :            : " hw_type={card_type_to_emulate}  (default CAC)\n"
    1516                 :            : " hw_params={param_for_card}      (default \"\")\n"
    1517                 :            : " nssemul                         (alias for use_hw=yes, hw_type=CAC)\n"
    1518                 :            : #if defined(ENABLE_PCSC)
    1519                 :            : " passthru                        (alias for use_hw=yes, hw_type=PASSTHRU)\n"
    1520                 :            : #endif
    1521                 :            : " soft=({slot_name},{vreader_name},{card_type_to_emulate},{params_for_card},\n"
    1522                 :            : "       {cert1},{cert2},{cert3}    (default none)\n"
    1523                 :            : "\n"
    1524                 :            : "  {nss_database}          The location of the NSS cert & key database\n"
    1525                 :            : "  {card_type_to_emulate}  What card interface to present to the guest\n"
    1526                 :            : "  {param_for_card}        Card interface specific parameters\n"
    1527                 :            : "  {slot_name}             NSS slot that contains the certs\n"
    1528                 :            : "  {vreader_name}          Virtual reader name to present to the guest\n"
    1529                 :            : "  {certN}                 Nickname of the certificate n on the virtual card\n"
    1530                 :            : "\n"
    1531                 :            : "These parameters come as a single string separated by blanks or newlines."
    1532                 :            : "\n"
    1533                 :            : "Unless use_hw is set to no, all tokens that look like removable hardware\n"
    1534                 :            : "tokens will be presented to the guest using the emulator specified by\n"
    1535                 :            : "hw_type, and parameters of hw_params. If use_hw is set to 'removable', "
    1536                 :            : "present any removable token.\n"
    1537                 :            : "\n"
    1538                 :            : "If more one or more soft= parameters are specified, these readers will be\n"
    1539                 :            : "presented to the guest\n"
    1540                 :            : #if defined(ENABLE_PCSC)
    1541                 :            : "\n"
    1542                 :            : "If a hw_type of PASSTHRU is given, a connection will be made to the hardware\n"
    1543                 :            : "using libpcscslite.  Note that in that case, no soft cards are permitted.\n"
    1544                 :            : #endif
    1545                 :            : );
    1546                 :          0 : }
    1547                 :            : /* vim: set ts=4 sw=4 tw=0 noet expandtab: */

Generated by: LCOV version 1.14