/* Decrypt the data in INDATA and return the allocated result in OUTDATA. If a PIN is required the PINCB will be used to ask for the PIN; it should return the PIN in an allocated buffer and put it into PIN. */ gpg_error_t app_decipher (app_t app, const char *keyidstr, gpg_error_t (*pincb)(void*, const char *, char **), void *pincb_arg, const void *indata, size_t indatalen, unsigned char **outdata, size_t *outdatalen ) { gpg_error_t err; if (!app || !indata || !indatalen || !outdata || !outdatalen || !pincb) return gpg_error (GPG_ERR_INV_VALUE); if (!app->ref_count) return gpg_error (GPG_ERR_CARD_NOT_INITIALIZED); if (!app->fnc.decipher) return gpg_error (GPG_ERR_UNSUPPORTED_OPERATION); err = lock_reader (app->slot, NULL /*FIXME*/); if (err) return err; err = app->fnc.decipher (app, keyidstr, pincb, pincb_arg, indata, indatalen, outdata, outdatalen); unlock_reader (app->slot); if (opt.verbose) log_info ("operation decipher result: %s\n", gpg_strerror (err)); return err; }
/* Perform the WRITEKEY operation. */ gpg_error_t app_writekey (app_t app, ctrl_t ctrl, const char *keyidstr, unsigned int flags, gpg_error_t (*pincb)(void*, const char *, char **), void *pincb_arg, const unsigned char *keydata, size_t keydatalen) { gpg_error_t err; if (!app || !keyidstr || !*keyidstr || !pincb) return gpg_error (GPG_ERR_INV_VALUE); if (!app->ref_count) return gpg_error (GPG_ERR_CARD_NOT_INITIALIZED); if (!app->fnc.writekey) return gpg_error (GPG_ERR_UNSUPPORTED_OPERATION); err = lock_reader (app->slot, ctrl); if (err) return err; err = app->fnc.writekey (app, ctrl, keyidstr, flags, pincb, pincb_arg, keydata, keydatalen); unlock_reader (app->slot); if (opt.verbose) log_info ("operation writekey result: %s\n", gpg_strerror (err)); return err; }
/* This may be called to tell this module about a removed or resetted card. */ void application_notify_card_reset (int slot) { app_t app; if (slot < 0 || slot >= DIM (lock_table)) return; /* FIXME: We are ignoring any error value here. */ lock_reader (slot, NULL); /* Mark application as non-reusable. */ if (lock_table[slot].app) lock_table[slot].app->no_reuse = 1; /* Deallocate a saved application for that slot, so that we won't try to reuse it. If there is no saved application, set a flag so that we won't save the current state. */ app = lock_table[slot].last_app; if (app) { lock_table[slot].last_app = NULL; deallocate_app (app); } unlock_reader (slot); }
int gpuvm_kernel_begin(void *hostptr, unsigned idev, int flags) { //fprintf(stderr, "beginning kernel\n"); // check arguments if(!hostptr) { fprintf(stderr, "gpuvm_kernel_begin: hostptr is NULL\n"); return GPUVM_ENULL; } if(idev >= ndevs_g) { fprintf(stderr, "gpuvm_kernel_begin: invalid device number\n"); return GPUVM_EARG; } if(flags != GPUVM_READ_WRITE && flags != GPUVM_READ_ONLY) { fprintf(stderr, "gpuvm_kernel_begin: invalid flags\n"); return GPUVM_EARG; } if(lock_reader()) return GPUVM_ERROR; // find host array host_array_t *host_array = host_array_find_by_ptr(hostptr); if(!host_array) { fprintf(stderr, "gpuvm_kernel_begin: hostptr %p is not registed with " "GPUVM\n", hostptr); unlock_reader(); return GPUVM_EHOSTPTR; } // copy data to device if needed int err; if(err = host_array_sync_to_device(host_array, idev, flags)) { unlock_reader(); return err; } if(unlock_reader()) return GPUVM_ERROR; return 0; } // gpuvm_kernel_begin
/* Free the resources associated with the application APP. APP is allowed to be NULL in which case this is a no-op. Note that we are using reference counting to track the users of the application and actually deferring the deallocation to allow for a later reuse by a new connection. */ void release_application (app_t app) { int slot; if (!app) return; if (!app->ref_count) log_bug ("trying to release an already released context\n"); if (--app->ref_count) return; /* Move the reference to the application in the lock table. */ slot = app->slot; /* FIXME: We are ignoring any error value. */ lock_reader (slot, NULL); if (lock_table[slot].app != app) { unlock_reader (slot); log_bug ("app mismatch %p/%p\n", app, lock_table[slot].app); deallocate_app (app); return; } if (lock_table[slot].last_app) deallocate_app (lock_table[slot].last_app); if (app->no_reuse) { /* If we shall not re-use the application we can't save it for later use. */ deallocate_app (app); lock_table[slot].last_app = NULL; } else lock_table[slot].last_app = lock_table[slot].app; lock_table[slot].app = NULL; unlock_reader (slot); }
/** pre-unlinks the host array by synchronizing it back to host and unprotecting it @param hostptr the address of the host array to be synchronized and unprotected @returns 0 if successful and a negative error code if not */ static int gpuvm_pre_unlink(void *hostptr) { if(lock_reader()) return GPUVM_ERROR; // get the array host_array_t *host_array = host_array_find_by_ptr(hostptr); if(!host_array) { unlock_reader(); fprintf(stderr, "gpuvm_pre_unlink: not a valid pointer\n"); return GPUVM_EHOSTPTR; } // tap into the beginning of each array subregion, to cause readback if // mprotected unsigned isubreg; int err; for(isubreg = 0; isubreg < host_array->nsubregs; isubreg++) { err += *(char*)host_array->subregs[isubreg]->range.ptr; } unlock_reader(); return 0; } // gpuvm_pre_unlink()
/* Perform a GET CHALLENGE operation. This fucntion is special as it directly accesses the card without any application specific wrapper. */ gpg_error_t app_get_challenge (app_t app, size_t nbytes, unsigned char *buffer) { gpg_error_t err; if (!app || !nbytes || !buffer) return gpg_error (GPG_ERR_INV_VALUE); if (!app->ref_count) return gpg_error (GPG_ERR_CARD_NOT_INITIALIZED); err = lock_reader (app->slot, NULL /*FIXME*/); if (err) return err; err = iso7816_get_challenge (app->slot, nbytes, buffer); unlock_reader (app->slot); return err; }
/* Read the certificate with id CERTID (as returned by learn_status in the CERTINFO status lines) and return it in the freshly allocated buffer put into CERT and the length of the certificate put into CERTLEN. */ gpg_error_t app_readcert (app_t app, const char *certid, unsigned char **cert, size_t *certlen) { gpg_error_t err; if (!app) return gpg_error (GPG_ERR_INV_VALUE); if (!app->ref_count) return gpg_error (GPG_ERR_CARD_NOT_INITIALIZED); if (!app->fnc.readcert) return gpg_error (GPG_ERR_UNSUPPORTED_OPERATION); err = lock_reader (app->slot, NULL/* FIXME*/); if (err) return err; err = app->fnc.readcert (app, certid, cert, certlen); unlock_reader (app->slot); return err; }
/* Perform a SETATTR operation. */ gpg_error_t app_setattr (app_t app, const char *name, gpg_error_t (*pincb)(void*, const char *, char **), void *pincb_arg, const unsigned char *value, size_t valuelen) { gpg_error_t err; if (!app || !name || !*name || !value) return gpg_error (GPG_ERR_INV_VALUE); if (!app->ref_count) return gpg_error (GPG_ERR_CARD_NOT_INITIALIZED); if (!app->fnc.setattr) return gpg_error (GPG_ERR_UNSUPPORTED_OPERATION); err = lock_reader (app->slot, NULL /*FIXME*/); if (err) return err; err = app->fnc.setattr (app, name, pincb, pincb_arg, value, valuelen); unlock_reader (app->slot); return err; }
void *gpuvm_xlate(void *hostptr, unsigned idev) { //fprintf(stderr, "xlating\n"); // check arguments if(!hostptr || idev >= ndevs_g) return 0; // lock for reading if(lock_reader()) return 0; // find host array and device buffer void *dev_buffer = 0; host_array_t *host_array = host_array_find_by_ptr(hostptr); if(host_array && host_array->links[idev]) dev_buffer = host_array->links[idev]->buf; // unlock and return if(unlock_reader()) return 0; return dev_buffer; } // gpuvm_xlate
/* Perform a VERIFY operation without doing anything lese. This may be used to initialze a the PIN cache for long lasting other operations. Its use is highly application dependent. */ gpg_error_t app_check_pin (app_t app, const char *keyidstr, gpg_error_t (*pincb)(void*, const char *, char **), void *pincb_arg) { gpg_error_t err; if (!app || !keyidstr || !*keyidstr || !pincb) return gpg_error (GPG_ERR_INV_VALUE); if (!app->ref_count) return gpg_error (GPG_ERR_CARD_NOT_INITIALIZED); if (!app->fnc.check_pin) return gpg_error (GPG_ERR_UNSUPPORTED_OPERATION); err = lock_reader (app->slot, NULL /*FIXME*/); if (err) return err; err = app->fnc.check_pin (app, keyidstr, pincb, pincb_arg); unlock_reader (app->slot); if (opt.verbose) log_info ("operation check_pin result: %s\n", gpg_strerror (err)); return err; }
/* Perform a GETATTR operation. */ gpg_error_t app_getattr (app_t app, ctrl_t ctrl, const char *name) { gpg_error_t err; if (!app || !name || !*name) return gpg_error (GPG_ERR_INV_VALUE); if (!app->ref_count) return gpg_error (GPG_ERR_CARD_NOT_INITIALIZED); if (app->apptype && name && !strcmp (name, "APPTYPE")) { send_status_info (ctrl, "APPTYPE", app->apptype, strlen (app->apptype), NULL, 0); return 0; } if (name && !strcmp (name, "SERIALNO")) { char *serial; time_t stamp; int rc; rc = app_get_serial_and_stamp (app, &serial, &stamp); if (rc) return rc; send_status_info (ctrl, "SERIALNO", serial, strlen (serial), NULL, 0); xfree (serial); return 0; } if (!app->fnc.getattr) return gpg_error (GPG_ERR_UNSUPPORTED_OPERATION); err = lock_reader (app->slot, ctrl); if (err) return err; err = app->fnc.getattr (app, ctrl, name); unlock_reader (app->slot); return err; }
/* Perform a CHANGE REFERENCE DATA or RESET RETRY COUNTER operation. */ gpg_error_t app_change_pin (app_t app, ctrl_t ctrl, const char *chvnostr, int reset_mode, gpg_error_t (*pincb)(void*, const char *, char **), void *pincb_arg) { gpg_error_t err; if (!app || !chvnostr || !*chvnostr || !pincb) return gpg_error (GPG_ERR_INV_VALUE); if (!app->ref_count) return gpg_error (GPG_ERR_CARD_NOT_INITIALIZED); if (!app->fnc.change_pin) return gpg_error (GPG_ERR_UNSUPPORTED_OPERATION); err = lock_reader (app->slot, ctrl); if (err) return err; err = app->fnc.change_pin (app, ctrl, chvnostr, reset_mode, pincb, pincb_arg); unlock_reader (app->slot); if (opt.verbose) log_info ("operation change_pin result: %s\n", gpg_strerror (err)); return err; }
/* Read the key with ID KEYID. On success a canonical encoded S-expression with the public key will get stored at PK and its length (for assertions) at PKLEN; the caller must release that buffer. On error NULL will be stored at PK and PKLEN and an error code returned. This function might not be supported by all applications. */ gpg_error_t app_readkey (app_t app, const char *keyid, unsigned char **pk, size_t *pklen) { gpg_error_t err; if (pk) *pk = NULL; if (pklen) *pklen = 0; if (!app || !keyid || !pk || !pklen) return gpg_error (GPG_ERR_INV_VALUE); if (!app->ref_count) return gpg_error (GPG_ERR_CARD_NOT_INITIALIZED); if (!app->fnc.readkey) return gpg_error (GPG_ERR_UNSUPPORTED_OPERATION); err = lock_reader (app->slot, NULL /*FIXME*/); if (err) return err; err= app->fnc.readkey (app, keyid, pk, pklen); unlock_reader (app->slot); return err; }
/* Write out the application specifig status lines for the LEARN command. */ gpg_error_t app_write_learn_status (app_t app, ctrl_t ctrl, unsigned int flags) { gpg_error_t err; if (!app) return gpg_error (GPG_ERR_INV_VALUE); if (!app->ref_count) return gpg_error (GPG_ERR_CARD_NOT_INITIALIZED); if (!app->fnc.learn_status) return gpg_error (GPG_ERR_UNSUPPORTED_OPERATION); /* We do not send APPTYPE if only keypairinfo is requested. */ if (app->apptype && !(flags & 1)) send_status_info (ctrl, "APPTYPE", app->apptype, strlen (app->apptype), NULL, 0); err = lock_reader (app->slot, ctrl); if (err) return err; err = app->fnc.learn_status (app, ctrl, flags); unlock_reader (app->slot); return err; }
/* If called with NAME as NULL, select the best fitting application and return a context; otherwise select the application with NAME and return a context. SLOT identifies the reader device. Returns an error code and stores NULL at R_APP if no application was found or no card is present. */ gpg_error_t select_application (ctrl_t ctrl, int slot, const char *name, app_t *r_app) { gpg_error_t err; app_t app = NULL; unsigned char *result = NULL; size_t resultlen; int want_undefined; (void)ctrl; *r_app = NULL; want_undefined = (name && !strcmp (name, "undefined")); err = lock_reader (slot, ctrl); if (err) return err; /* First check whether we already have an application to share. */ app = lock_table[slot].initialized ? lock_table[slot].app : NULL; if (app && name) if (!app->apptype || ascii_strcasecmp (app->apptype, name)) { unlock_reader (slot); if (app->apptype) log_info ("application '%s' in use by reader %d - can't switch\n", app->apptype, slot); return gpg_error (GPG_ERR_CONFLICT); } /* Don't use a non-reusable marked application. */ if (app && app->no_reuse) { unlock_reader (slot); log_info ("lingering application '%s' in use by reader %d" " - can't switch\n", app->apptype? app->apptype:"?", slot); return gpg_error (GPG_ERR_CONFLICT); } /* If we don't have an app, check whether we have a saved application for that slot. This is useful so that a card does not get reset even if only one session is using the card - this way the PIN cache and other cached data are preserved. */ if (!app && lock_table[slot].initialized && lock_table[slot].last_app) { app = lock_table[slot].last_app; if (!name || (app->apptype && !ascii_strcasecmp (app->apptype, name)) ) { /* Yes, we can reuse this application - either the caller requested an unspecific one or the requested one matches the saved one. */ lock_table[slot].app = app; lock_table[slot].last_app = NULL; } else { /* No, this saved application can't be used - deallocate it. */ lock_table[slot].last_app = NULL; deallocate_app (app); app = NULL; } } /* If we can reuse an application, bump the reference count and return it. */ if (app) { if (app->slot != slot) log_bug ("slot mismatch %d/%d\n", app->slot, slot); app->slot = slot; app->ref_count++; *r_app = app; unlock_reader (slot); return 0; /* Okay: We share that one. */ } /* Need to allocate a new one. */ app = xtrycalloc (1, sizeof *app); if (!app) { err = gpg_error_from_syserror (); log_info ("error allocating context: %s\n", gpg_strerror (err)); unlock_reader (slot); return err; } app->slot = slot; /* Fixme: We should now first check whether a card is at all present. */ /* Try to read the GDO file first to get a default serial number. We skip this if the undefined application has been requested. */ if (!want_undefined) { err = iso7816_select_file (slot, 0x3F00, 1, NULL, NULL); if (!err) err = iso7816_select_file (slot, 0x2F02, 0, NULL, NULL); if (!err) err = iso7816_read_binary (slot, 0, 0, &result, &resultlen); if (!err) { size_t n; const unsigned char *p; p = find_tlv_unchecked (result, resultlen, 0x5A, &n); if (p) resultlen -= (p-result); if (p && n > resultlen && n == 0x0d && resultlen+1 == n) { /* The object it does not fit into the buffer. This is an invalid encoding (or the buffer is too short. However, I have some test cards with such an invalid encoding and therefore I use this ugly workaround to return something I can further experiment with. */ log_info ("enabling BMI testcard workaround\n"); n--; } if (p && n <= resultlen) { /* The GDO file is pretty short, thus we simply reuse it for storing the serial number. */ memmove (result, p, n); app->serialno = result; app->serialnolen = n; err = app_munge_serialno (app); if (err) goto leave; } else xfree (result); result = NULL; } } /* For certain error codes, there is no need to try more. */ if (gpg_err_code (err) == GPG_ERR_CARD_NOT_PRESENT || gpg_err_code (err) == GPG_ERR_ENODEV) goto leave; /* Figure out the application to use. */ if (want_undefined) { /* We switch to the "undefined" application only if explicitly requested. */ app->apptype = "UNDEFINED"; err = 0; } else err = gpg_error (GPG_ERR_NOT_FOUND); if (err && is_app_allowed ("openpgp") && (!name || !strcmp (name, "openpgp"))) err = app_select_openpgp (app); if (err && is_app_allowed ("nks") && (!name || !strcmp (name, "nks"))) err = app_select_nks (app); if (err && is_app_allowed ("p15") && (!name || !strcmp (name, "p15"))) err = app_select_p15 (app); if (err && is_app_allowed ("geldkarte") && (!name || !strcmp (name, "geldkarte"))) err = app_select_geldkarte (app); if (err && is_app_allowed ("dinsig") && (!name || !strcmp (name, "dinsig"))) err = app_select_dinsig (app); if (err && name) err = gpg_error (GPG_ERR_NOT_SUPPORTED); leave: if (err) { if (name) log_info ("can't select application '%s': %s\n", name, gpg_strerror (err)); else log_info ("no supported card application found: %s\n", gpg_strerror (err)); xfree (app); unlock_reader (slot); return err; } app->ref_count = 1; lock_table[slot].app = app; *r_app = app; unlock_reader (slot); return 0; }