LCOV - code coverage report
Current view: top level - src - vcard_emul_nss.c (source / functions) Coverage Total Hit
Test: Code coverage Lines: 75.8 % 545 413
Test Date: 2025-12-04 16:15:14 Functions: 90.9 % 33 30
Legend: Lines: hit not hit | Branches: + taken - not taken # not executed Branches: 55.7 % 336 187

             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                 :           0 : vcard_emul_map_error(int error)
     194                 :             : {
     195   [ #  #  #  # ]:           0 :     switch (error) {
     196                 :             :     case SEC_ERROR_TOKEN_NOT_LOGGED_IN:
     197                 :             :         return VCARD7816_STATUS_ERROR_CONDITION_NOT_SATISFIED;
     198                 :           0 :     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                 :           0 :         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                 :           0 :         ret = vcard_emul_map_error(PORT_GetError());
     358                 :           0 :         goto cleanup;
     359                 :             :     }
     360                 :           3 :     pad_len = buffer_size - signature_len;
     361         [ -  + ]:           3 :     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                 :           3 :     buffer[0] = 0;
     370                 :           3 :     buffer[1] = 2; /* RSA_encrypt  */
     371                 :           3 :     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                 :           3 :     memset(&buffer[2], 0x03, pad_len);
     380                 :           3 :     pad_len += 2; /* index to the end of the pad */
     381                 :           3 :     buffer[pad_len] = 0;
     382                 :             :     pad_len++; /* index to the start of the data */
     383                 :           3 :     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                 :           3 :     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         [ +  + ]:          80 :         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 :                 if (args == NULL || *args == 0) {
    1357                 :           0 :                     fprintf(stderr, "Error: missing cert name.\n");
    1358                 :           0 :                     goto fail;
    1359                 :             :                 }
    1360                 :          15 :                 vreaderOpt->cert_name[i] = g_strndup(cert, args - cert);
    1361                 :          15 :                 args = strip(args+1);
    1362                 :             :             }
    1363         [ -  + ]:           5 :             if (*args == ')') {
    1364                 :           0 :                 args++;
    1365                 :             :             }
    1366                 :           5 :             opts->vreader_count++;
    1367                 :             :         /* use_hw= */
    1368         [ +  + ]:          17 :         } else if (strncmp(args, "use_hw=", 7) == 0) {
    1369                 :           8 :             args = strip(args+7);
    1370         [ +  + ]:           8 :             if (*args == '0' || *args == 'N' || *args == 'n' || *args == 'F') {
    1371                 :           5 :                 opts->use_hw = USE_HW_NO;
    1372         [ +  - ]:           3 :             } else if (strncmp(args, "removable", 9) == 0) {
    1373                 :           3 :                 opts->use_hw = USE_HW_REMOVABLE;
    1374                 :             :             } else {
    1375                 :           0 :                 opts->use_hw = USE_HW_YES;
    1376                 :             :             }
    1377                 :           8 :             args = find_blank(args);
    1378                 :             :         /* hw_type= */
    1379         [ -  + ]:           9 :         } else if (strncmp(args, "hw_type=", 8) == 0) {
    1380                 :           0 :             args = strip(args+8);
    1381                 :           0 :             opts->hw_card_type = vcard_emul_type_from_string(args);
    1382         [ #  # ]:           0 :             if (opts->hw_card_type == VCARD_EMUL_NONE) {
    1383                 :           0 :                 fprintf(stderr, "Error: invalid smartcard type '%s'.\n",
    1384                 :             :                         args);
    1385                 :           0 :                 goto fail;
    1386                 :             :             }
    1387                 :           0 :             args = find_blank(args);
    1388                 :             :         /* hw_params= */
    1389         [ -  + ]:           9 :         } else if (strncmp(args, "hw_params=", 10) == 0) {
    1390                 :             :             const char *params;
    1391                 :             : 
    1392         [ #  # ]:           0 :             if (opts->hw_type_params != NULL) {
    1393                 :           0 :                 fprintf(stderr, "Error: redefinition of hw_params= is not allowed.\n");
    1394                 :           0 :                 goto fail;
    1395                 :             :             }
    1396                 :           0 :             args = strip(args+10);
    1397                 :             :             params = args;
    1398                 :           0 :             args = find_blank(args);
    1399                 :           0 :             opts->hw_type_params = g_strndup(params, args-params);
    1400                 :             :         /* db="/data/base/path" */
    1401         [ +  + ]:           9 :         } else if (strncmp(args, "db=", 3) == 0) {
    1402                 :             :             const char *db;
    1403                 :             : 
    1404         [ -  + ]:           8 :             if (opts->nss_db != NULL) {
    1405                 :           0 :                 fprintf(stderr, "Error: redefinition of db= is not allowed.\n");
    1406                 :           0 :                 goto fail;
    1407                 :             :             }
    1408                 :           8 :             args = strip(args+3);
    1409         [ -  + ]:           8 :             if (*args != '"') {
    1410                 :           0 :                 fprintf(stderr, "Error: you must quote the file path.\n");
    1411                 :           0 :                 goto fail;
    1412                 :             :             }
    1413                 :           8 :             args++;
    1414                 :             :             db = args;
    1415                 :           8 :             args = strpbrk(args, "\"\n");
    1416         [ -  + ]:           8 :             if (args == NULL) {
    1417                 :           0 :                 fprintf(stderr, "Error: invalid db argument.\n");
    1418                 :           0 :                 goto fail;
    1419                 :             :             }
    1420                 :           8 :             opts->nss_db = g_strndup(db, args-db);
    1421         [ +  - ]:           8 :             if (*args != 0) {
    1422                 :           8 :                 args++;
    1423                 :             :             }
    1424         [ -  + ]:           1 :         } else if (strncmp(args, "nssemul", 7) == 0) {
    1425                 :           0 :             opts->hw_card_type = VCARD_EMUL_CAC;
    1426                 :           0 :             opts->use_hw = USE_HW_YES;
    1427                 :           0 :             args = find_blank(args + 7);
    1428                 :             : #if defined(ENABLE_PCSC)
    1429                 :             :         } else if (strncmp(args, "passthru", 8) == 0) {
    1430                 :             :             opts->hw_card_type = VCARD_EMUL_PASSTHRU;
    1431                 :             :             opts->use_hw = USE_HW_YES;
    1432                 :             :             args = find_blank(args + 8);
    1433                 :             : #endif
    1434                 :             :         } else {
    1435                 :           1 :             fprintf(stderr, "Error: Unknown smartcard specification.\n");
    1436                 :           1 :             goto fail;
    1437                 :             :         }
    1438         [ +  + ]:          21 :     } while (*args != 0);
    1439                 :             : 
    1440                 :             :     return opts;
    1441                 :             : 
    1442                 :             : fail:
    1443                 :             :     /* Clean up what was allocated above on failure */
    1444         [ -  + ]:           1 :     for (i = 0; i < opts->vreader_count; i++) {
    1445                 :           0 :         g_free(opts->vreader[i].name);
    1446                 :           0 :         g_free(opts->vreader[i].vname);
    1447                 :           0 :         g_free(opts->vreader[i].type_params);
    1448         [ #  # ]:           0 :         for (j = 0; j < opts->vreader[i].cert_count; j++) {
    1449                 :           0 :             g_free(opts->vreader[i].cert_name[j]);
    1450                 :             :         }
    1451                 :           0 :         g_free(opts->vreader[i].cert_name);
    1452                 :             :     }
    1453                 :           1 :     g_free(opts->vreader);
    1454                 :           1 :     g_free(opts->hw_type_params);
    1455                 :           1 :     g_free(opts->nss_db);
    1456                 :           1 :     return NULL;
    1457                 :             : }
    1458                 :             : 
    1459                 :             : unsigned char *
    1460                 :           6 : vcard_emul_read_object(VCard *card, const char *label,
    1461                 :             :     unsigned int *ret_len)
    1462                 :             : {
    1463                 :             :     PK11SlotInfo *slot;
    1464                 :             :     PK11GenericObject *obj, *firstObj, *myObj = NULL;
    1465                 :             :     SECItem result;
    1466                 :             :     SECStatus r;
    1467                 :             :     unsigned char *ret;
    1468                 :             : 
    1469                 :             :     slot = vcard_emul_card_get_slot(card);
    1470                 :             : 
    1471                 :           6 :     firstObj = PK11_FindGenericObjects(slot, CKO_DATA);
    1472                 :           6 :     g_debug("%s: Search for generic objects: got %p", __func__, firstObj);
    1473         [ -  + ]:           6 :     for (obj = firstObj; obj; obj = PK11_GetNextGenericObject(obj)) {
    1474                 :             :         int found = 0;
    1475                 :           0 :         r = PK11_ReadRawAttribute(PK11_TypeGeneric, obj,
    1476                 :             :             CKA_LABEL, &result);
    1477         [ #  # ]:           0 :         if (r != SECSuccess) {
    1478                 :           0 :             PK11_DestroyGenericObjects(firstObj);
    1479                 :           0 :             return NULL;
    1480                 :             :         }
    1481                 :             : 
    1482         [ #  # ]:           0 :         if (strlen(label) == result.len
    1483         [ #  # ]:           0 :             && memcmp(label, result.data, result.len) == 0)
    1484                 :             :             found = 1;
    1485                 :             : 
    1486                 :           0 :         PORT_Free(result.data);
    1487                 :           0 :         result.data = NULL;
    1488                 :             : 
    1489         [ #  # ]:           0 :         if (found) {
    1490                 :           0 :             PK11_UnlinkGenericObject(obj);
    1491                 :             :             myObj = obj;
    1492                 :           0 :             break;
    1493                 :             :         }
    1494                 :             :     }
    1495                 :           6 :     PK11_DestroyGenericObjects(firstObj);
    1496                 :             : 
    1497         [ +  - ]:           6 :     if (!myObj)
    1498                 :             :         return NULL;
    1499                 :             : 
    1500                 :           0 :     r = PK11_ReadRawAttribute(PK11_TypeGeneric, myObj,
    1501                 :             :         CKA_VALUE, &result);
    1502                 :           0 :     PK11_DestroyGenericObject(myObj);
    1503         [ #  # ]:           0 :     if (r != SECSuccess)
    1504                 :             :         return NULL;
    1505                 :             : 
    1506                 :           0 :     *ret_len = result.len;
    1507                 :           0 :     ret = g_memdup2(result.data, result.len);
    1508                 :           0 :     PORT_Free(result.data);
    1509                 :           0 :     return ret;
    1510                 :             : }
    1511                 :             : 
    1512                 :             : void
    1513                 :           0 : vcard_emul_usage(void)
    1514                 :             : {
    1515                 :           0 :    fprintf(stderr,
    1516                 :             : "emul args: comma separated list of the following arguments\n"
    1517                 :             : " db={nss_database}               (default sql:/etc/pki/nssdb)\n"
    1518                 :             : " use_hw=[yes|no|removable]       (default yes)\n"
    1519                 :             : " hw_type={card_type_to_emulate}  (default CAC)\n"
    1520                 :             : " hw_params={param_for_card}      (default \"\")\n"
    1521                 :             : " nssemul                         (alias for use_hw=yes, hw_type=CAC)\n"
    1522                 :             : #if defined(ENABLE_PCSC)
    1523                 :             : " passthru                        (alias for use_hw=yes, hw_type=PASSTHRU)\n"
    1524                 :             : #endif
    1525                 :             : " soft=({slot_name},{vreader_name},{card_type_to_emulate},{params_for_card},\n"
    1526                 :             : "       {cert1},{cert2},{cert3}    (default none)\n"
    1527                 :             : "\n"
    1528                 :             : "  {nss_database}          The location of the NSS cert & key database\n"
    1529                 :             : "  {card_type_to_emulate}  What card interface to present to the guest\n"
    1530                 :             : "  {param_for_card}        Card interface specific parameters\n"
    1531                 :             : "  {slot_name}             NSS slot that contains the certs\n"
    1532                 :             : "  {vreader_name}          Virtual reader name to present to the guest\n"
    1533                 :             : "  {certN}                 Nickname of the certificate n on the virtual card\n"
    1534                 :             : "\n"
    1535                 :             : "These parameters come as a single string separated by blanks or newlines."
    1536                 :             : "\n"
    1537                 :             : "Unless use_hw is set to no, all tokens that look like removable hardware\n"
    1538                 :             : "tokens will be presented to the guest using the emulator specified by\n"
    1539                 :             : "hw_type, and parameters of hw_params. If use_hw is set to 'removable', "
    1540                 :             : "present any removable token.\n"
    1541                 :             : "\n"
    1542                 :             : "If more one or more soft= parameters are specified, these readers will be\n"
    1543                 :             : "presented to the guest\n"
    1544                 :             : #if defined(ENABLE_PCSC)
    1545                 :             : "\n"
    1546                 :             : "If a hw_type of PASSTHRU is given, a connection will be made to the hardware\n"
    1547                 :             : "using libpcscslite.  Note that in that case, no soft cards are permitted.\n"
    1548                 :             : #endif
    1549                 :             : );
    1550                 :           0 : }
    1551                 :             : /* vim: set ts=4 sw=4 tw=0 noet expandtab: */
        

Generated by: LCOV version 2.0-1