Exemple #1
0
/*********************************************************************
 *
 * i n s t a l l _ c e r t
 *
 * Installs the cert in the permanent database.
 */
static CERTCertificate*
install_cert(CERTCertDBHandle *db, SECItem *derCert, char *nickname)
{
    CERTCertificate * newcert;
    PK11SlotInfo * newSlot;


    newSlot = PK11_ImportDERCertForKey(derCert, nickname, &pwdata);
    if ( newSlot == NULL ) {
	PR_fprintf(errorFD, "Unable to install certificate\n");
	errorCount++;
	exit(ERRX);
    }

    newcert = PK11_FindCertFromDERCertItem(newSlot, derCert, &pwdata);
    PK11_FreeSlot(newSlot);
    if (newcert == NULL) {
	PR_fprintf(errorFD, "%s: can't find new certificate\n",
	     PROGRAM_NAME);
	errorCount++;
	exit (ERRX);
    }

    if (verbosity >= 0) {
	PR_fprintf(outputFD, "certificate \"%s\" added to database\n",
	     nickname);
    }

    return newcert;
}
Exemple #2
0
/**
 *
 * Callback to pick the SSL client certificate.
 */
static SECStatus SelectClientCert(void *arg, PRFileDesc *sock,
                                  struct CERTDistNamesStr *caNames,
                                  struct CERTCertificateStr **pRetCert,
                                  struct SECKEYPrivateKeyStr **pRetKey)
{
  struct ssl_connect_data *connssl = (struct ssl_connect_data *)arg;
  struct SessionHandle *data = connssl->data;
  const char *nickname = connssl->client_nickname;

  if(connssl->obj_clicert) {
    /* use the cert/key provided by PEM reader */
    static const char pem_slotname[] = "PEM Token #1";
    SECItem cert_der = { 0, NULL, 0 };
    void *proto_win = SSL_RevealPinArg(sock);
    struct CERTCertificateStr *cert;
    struct SECKEYPrivateKeyStr *key;

    PK11SlotInfo *slot = PK11_FindSlotByName(pem_slotname);
    if(NULL == slot) {
      failf(data, "NSS: PK11 slot not found: %s", pem_slotname);
      return SECFailure;
    }

    if(PK11_ReadRawAttribute(PK11_TypeGeneric, connssl->obj_clicert, CKA_VALUE,
                             &cert_der) != SECSuccess) {
      failf(data, "NSS: CKA_VALUE not found in PK11 generic object");
      PK11_FreeSlot(slot);
      return SECFailure;
    }

    cert = PK11_FindCertFromDERCertItem(slot, &cert_der, proto_win);
    SECITEM_FreeItem(&cert_der, PR_FALSE);
    if(NULL == cert) {
      failf(data, "NSS: client certificate from file not found");
      PK11_FreeSlot(slot);
      return SECFailure;
    }

    key = PK11_FindPrivateKeyFromCert(slot, cert, NULL);
    PK11_FreeSlot(slot);
    if(NULL == key) {
      failf(data, "NSS: private key from file not found");
      CERT_DestroyCertificate(cert);
      return SECFailure;
    }

    infof(data, "NSS: client certificate from file\n");
    display_cert_info(data, cert);

    *pRetCert = cert;
    *pRetKey = key;
    return SECSuccess;
  }

  /* use the default NSS hook */
  if(SECSuccess != NSS_GetClientAuthData((void *)nickname, sock, caNames,
                                          pRetCert, pRetKey)
      || NULL == *pRetCert) {

    if(NULL == nickname)
      failf(data, "NSS: client certificate not found (nickname not "
            "specified)");
    else
      failf(data, "NSS: client certificate not found: %s", nickname);

    return SECFailure;
  }

  /* get certificate nickname if any */
  nickname = (*pRetCert)->nickname;
  if(NULL == nickname)
    nickname = "[unknown]";

  if(NULL == *pRetKey) {
    failf(data, "NSS: private key not found for certificate: %s", nickname);
    return SECFailure;
  }

  infof(data, "NSS: using client certificate: %s\n", nickname);
  display_cert_info(data, *pRetCert);
  return SECSuccess;
}
// Based on nsPKCS12Blob::ImportFromFileHelper.
int
nsPKCS12Blob_ImportHelper(const char* pkcs12_data,
                          size_t pkcs12_len,
                          const base::string16& password,
                          bool is_extractable,
                          bool try_zero_length_secitem,
                          PK11SlotInfo *slot,
                          net::CertificateList* imported_certs)
{
    DCHECK(pkcs12_data);
    DCHECK(slot);
    int import_result = net::ERR_PKCS12_IMPORT_FAILED;
    SECStatus srv = SECSuccess;
    SEC_PKCS12DecoderContext *dcx = NULL;
    SECItem unicodePw;
    SECItem attribute_value;
    CK_BBOOL attribute_data = CK_FALSE;
    const SEC_PKCS12DecoderItem* decoder_item = NULL;

    unicodePw.type = siBuffer;
    unicodePw.len = 0;
    unicodePw.data = NULL;
    if (!try_zero_length_secitem) {
        unicodeToItem(password.c_str(), &unicodePw);
    }

    // Initialize the decoder
    dcx = SEC_PKCS12DecoderStart(&unicodePw, slot,
                                 // wincx
                                 NULL,
                                 // dOpen, dClose, dRead, dWrite, dArg: NULL
                                 // specifies default impl using memory buffer.
                                 NULL, NULL, NULL, NULL, NULL);
    if (!dcx) {
        srv = SECFailure;
        goto finish;
    }
    // feed input to the decoder
    srv = SEC_PKCS12DecoderUpdate(dcx,
                                  (unsigned char*)pkcs12_data,
                                  pkcs12_len);
    if (srv) goto finish;
    // verify the blob
    srv = SEC_PKCS12DecoderVerify(dcx);
    if (srv) goto finish;
    // validate bags
    srv = SEC_PKCS12DecoderValidateBags(dcx, nickname_collision);
    if (srv) goto finish;
    // import certificate and key
    srv = SEC_PKCS12DecoderImportBags(dcx);
    if (srv) goto finish;

    attribute_value.data = &attribute_data;
    attribute_value.len = sizeof(attribute_data);

    srv = SEC_PKCS12DecoderIterateInit(dcx);
    if (srv) goto finish;

    if (imported_certs)
        imported_certs->clear();

    // Collect the list of decoded certificates, and mark private keys
    // non-extractable if needed.
    while (SEC_PKCS12DecoderIterateNext(dcx, &decoder_item) == SECSuccess) {
        if (decoder_item->type != SEC_OID_PKCS12_V1_CERT_BAG_ID)
            continue;

        CERTCertificate* cert = PK11_FindCertFromDERCertItem(
                                    slot, decoder_item->der,
                                    NULL);  // wincx
        if (!cert) {
            LOG(ERROR) << "Could not grab a handle to the certificate in the slot "
                       << "from the corresponding PKCS#12 DER certificate.";
            continue;
        }

        // Add the cert to the list
        if (imported_certs) {
            // Empty list of intermediates.
            net::X509Certificate::OSCertHandles intermediates;
            imported_certs->push_back(
                net::X509Certificate::CreateFromHandle(cert, intermediates));
        }

        // Once we have determined that the imported certificate has an
        // associated private key too, only then can we mark the key as
        // non-extractable.
        if (!decoder_item->hasKey) {
            CERT_DestroyCertificate(cert);
            continue;
        }

        // Iterate through all the imported PKCS12 items and mark any accompanying
        // private keys as non-extractable.
        if (!is_extractable) {
            SECKEYPrivateKey* privKey = PK11_FindPrivateKeyFromCert(slot, cert,
                                        NULL);  // wincx
            if (privKey) {
                // Mark the private key as non-extractable.
                srv = PK11_WriteRawAttribute(PK11_TypePrivKey, privKey, CKA_EXTRACTABLE,
                                             &attribute_value);
                SECKEY_DestroyPrivateKey(privKey);
                if (srv) {
                    LOG(ERROR) << "Could not set CKA_EXTRACTABLE attribute on private "
                               << "key.";
                    CERT_DestroyCertificate(cert);
                    break;
                }
            }
        }
        CERT_DestroyCertificate(cert);
        if (srv) goto finish;
    }
    import_result = net::OK;
finish:
    // If srv != SECSuccess, NSS probably set a specific error code.
    // We should use that error code instead of inventing a new one
    // for every error possible.
    if (srv != SECSuccess) {
        int error = PORT_GetError();
        LOG(ERROR) << "PKCS#12 import failed with error " << error;
        switch (error) {
        case SEC_ERROR_BAD_PASSWORD:
        case SEC_ERROR_PKCS12_PRIVACY_PASSWORD_INCORRECT:
            import_result = net::ERR_PKCS12_IMPORT_BAD_PASSWORD;
            break;
        case SEC_ERROR_PKCS12_INVALID_MAC:
            import_result = net::ERR_PKCS12_IMPORT_INVALID_MAC;
            break;
        case SEC_ERROR_BAD_DER:
        case SEC_ERROR_PKCS12_DECODING_PFX:
        case SEC_ERROR_PKCS12_CORRUPT_PFX_STRUCTURE:
            import_result = net::ERR_PKCS12_IMPORT_INVALID_FILE;
            break;
        case SEC_ERROR_PKCS12_UNSUPPORTED_MAC_ALGORITHM:
        case SEC_ERROR_PKCS12_UNSUPPORTED_TRANSPORT_MODE:
        case SEC_ERROR_PKCS12_UNSUPPORTED_PBE_ALGORITHM:
        case SEC_ERROR_PKCS12_UNSUPPORTED_VERSION:
            import_result = net::ERR_PKCS12_IMPORT_UNSUPPORTED;
            break;
        default:
            import_result = net::ERR_PKCS12_IMPORT_FAILED;
            break;
        }
    }
    // Finish the decoder
    if (dcx)
        SEC_PKCS12DecoderFinish(dcx);
    SECITEM_ZfreeItem(&unicodePw, PR_FALSE);
    return import_result;
}