PRStatus PR_CALLBACK
nsNSSComponent::IdentityInfoInit()
{
  for (size_t iEV=0; iEV < (sizeof(myTrustedEVInfos)/sizeof(nsMyTrustedEVInfo)); ++iEV) {
    nsMyTrustedEVInfo &entry = myTrustedEVInfos[iEV];
    if (!entry.oid_name) // invalid or placeholder list entry
      continue;

    SECStatus rv;
    CERTIssuerAndSN ias;

    rv = ATOB_ConvertAsciiToItem(&ias.derIssuer, const_cast<char*>(entry.issuer_base64));
    NS_ASSERTION(rv==SECSuccess, "error converting ascii to binary.");
    rv = ATOB_ConvertAsciiToItem(&ias.serialNumber, const_cast<char*>(entry.serial_base64));
    NS_ASSERTION(rv==SECSuccess, "error converting ascii to binary.");

    entry.cert = CERT_FindCertByIssuerAndSN(nsnull, &ias);
    NS_ASSERTION(entry.cert, "Could not find EV root in NSS storage");

    if (!entry.cert)
      continue;

    nsNSSCertificate c(entry.cert);
    nsAutoString fingerprint;
    c.GetSha1Fingerprint(fingerprint);

    NS_ConvertASCIItoUTF16 sha1(entry.ev_root_sha1_fingerprint);

    if (sha1 != fingerprint) {
      NS_ASSERTION(sha1 == fingerprint, "found EV root with unexpected SHA1 mismatch");
      CERT_DestroyCertificate(entry.cert);
      entry.cert = nsnull;
      continue;
    }

    SECItem ev_oid_item;
    ev_oid_item.data = nsnull;
    ev_oid_item.len = 0;
    SECStatus srv = SEC_StringToOID(nsnull, &ev_oid_item, 
                                    entry.dotted_oid, 0);
    if (srv != SECSuccess)
      continue;

    entry.oid_tag = register_oid(&ev_oid_item, entry.oid_name);

    SECITEM_FreeItem(&ev_oid_item, PR_FALSE);
  }

#ifdef PSM_ENABLE_TEST_EV_ROOTS
  if (!testEVInfosLoaded) {
    testEVInfosLoaded = PR_TRUE;
    testEVInfos = new testEVArray;
    if (testEVInfos) {
      loadTestEVInfos();
    }
  }
#endif

  return PR_SUCCESS;
}
Esempio n. 2
0
char *oauth_sign_rsa_sha1 (const char *m, const char *k) {
  PK11SlotInfo      *slot = NULL;
  SECKEYPrivateKey  *pkey = NULL;
  SECItem            signature;
  SECStatus          s;
  SECItem            der;
  char              *rv=NULL;

  char *key = oauth_strip_pkcs(k, NS_PRIV_HEADER, NS_PRIV_TRAILER); 
  if (!key) return NULL;

  oauth_init_nss();

  slot = PK11_GetInternalKeySlot();
  if (!slot) goto looser;
  s = ATOB_ConvertAsciiToItem(&der, key);
  if (s != SECSuccess) goto looser;
  s = PK11_ImportDERPrivateKeyInfoAndReturnKey(slot, &der, NULL, NULL, PR_FALSE, PR_TRUE, KU_ALL, &pkey, NULL);
  SECITEM_FreeItem(&der, PR_FALSE);
  if (s != SECSuccess) goto looser;
  if (!pkey) goto looser;
  if (pkey->keyType != rsaKey) goto looser;
  s = SEC_SignData(&signature, (unsigned char*) m, strlen(m), pkey, SEC_OID_ISO_SHA1_WITH_RSA_SIGNATURE);
  if (s != SECSuccess) goto looser;

  rv=oauth_encode_base64(signature.len, signature.data);
  SECITEM_FreeItem(&signature, PR_FALSE);

looser:
  if (pkey) SECKEY_DestroyPrivateKey(pkey);
  if (slot) PK11_FreeSlot(slot);
  free(key);
  return rv;
}
Esempio n. 3
0
static SECStatus nss_load_crl(const char* crlfilename)
{
  PRFileDesc *infile;
  PRFileInfo  info;
  SECItem filedata = { 0, NULL, 0 };
  SECItem crlDER = { 0, NULL, 0 };
  char *body;

  infile = PR_Open(crlfilename, PR_RDONLY, 0);
  if(!infile)
    return SECFailure;

  if(PR_SUCCESS != PR_GetOpenFileInfo(infile, &info))
    goto fail;

  if(!SECITEM_AllocItem(NULL, &filedata, info.size + /* zero ended */ 1))
    goto fail;

  if(info.size != PR_Read(infile, filedata.data, info.size))
    goto fail;

  /* place a trailing zero right after the visible data */
  body = (char*)filedata.data;
  body[--filedata.len] = '\0';

  body = strstr(body, "-----BEGIN");
  if(body) {
    /* assume ASCII */
    char *trailer;
    char *begin = PORT_Strchr(body, '\n');
    if(!begin)
      begin = PORT_Strchr(body, '\r');
    if(!begin)
      goto fail;

    trailer = strstr(++begin, "-----END");
    if(!trailer)
      goto fail;

    /* retrieve DER from ASCII */
    *trailer = '\0';
    if(ATOB_ConvertAsciiToItem(&crlDER, begin))
      goto fail;

    SECITEM_FreeItem(&filedata, PR_FALSE);
  }
  else
    /* assume DER */
    crlDER = filedata;

  PR_Close(infile);
  return nss_cache_crl(&crlDER);

fail:
  PR_Close(infile);
  SECITEM_FreeItem(&filedata, PR_FALSE);
  return SECFailure;
}
Esempio n. 4
0
SECStatus
SECU_ReadDERFromFile(SECItem *der, PRFileDesc *inFile, PRBool ascii)
{
    SECStatus rv;
    if (ascii) {
    /* First convert ascii to binary */
    SECItem filedata;
    char *asc, *body;

    /* Read in ascii data */
    rv = SECU_FileToItem(&filedata, inFile);
    asc = (char *)filedata.data;
    if (!asc) {
        fprintf(stderr, "unable to read data from input file\n");
        return SECFailure;
    }

    /* check for headers and trailers and remove them */
    if ((body = strstr(asc, "-----BEGIN")) != NULL) {
        char *trailer = NULL;
        asc = body;
        body = PORT_Strchr(body, '\n');
        if (!body)
            body = PORT_Strchr(asc, '\r'); /* maybe this is a MAC file */
        if (body)
            trailer = strstr(++body, "-----END");
        if (trailer != NULL) {
            *trailer = '\0';
        } else {
            fprintf(stderr, "input has header but no trailer\n");
            PORT_Free(filedata.data);
            return SECFailure;
        }
    } else {
        body = asc;
    }
     
    /* Convert to binary */
    rv = ATOB_ConvertAsciiToItem(der, body);
    if (rv) {
        fprintf(stderr, "error converting ascii to binary (%d)\n",
            PORT_GetError());
        PORT_Free(filedata.data);
        return SECFailure;
    }

    PORT_Free(filedata.data);
    } else {
        /* Read in binary der */
        rv = SECU_FileToItem(der, inFile);
        if (rv) {
            fprintf(stderr, "error converting der (%d)\n", 
                PORT_GetError());
            return SECFailure;
        }
    }
    return SECSuccess;
}
Esempio n. 5
0
UtlBoolean SmimeBody::convertPemToDer(UtlString& pemData,
                                      UtlString& derData)
{
    UtlBoolean conversionSucceeded = FALSE;
    derData.remove(0);

#ifdef ENABLE_NSS_SMIME
    // Code from NSS secutil.c

    char* body = NULL;
    char* pemDataPtr = (char*) pemData.data();

	/* check for headers and trailers and remove them */
	if ((body = strstr(pemDataPtr, "-----BEGIN")) != NULL) {
	    char *trailer = NULL;
	    pemData = strdup(body);
	    body = PORT_Strchr(body, '\n');
	    if (!body)
		body = PORT_Strchr(pemDataPtr, '\r'); /* maybe this is a MAC file */
	    if (body)
		trailer = strstr(++body, "-----END");
	    if (trailer != NULL) {
		*trailer = '\0';
	    } else {
		Os::Logger::instance().log(FAC_SIP, PRI_ERR,
            "input has header but no trailer\n");
	    }
	} else {
	    body = pemDataPtr;
	}

	/* Convert to binary */
    SECItem derItem;
    derItem.data = NULL;
    derItem.len = 0;
	if(ATOB_ConvertAsciiToItem(&derItem, body))
    {
        Os::Logger::instance().log(FAC_SIP, PRI_ERR,
            "error converting PEM base64 data to binary");
    }
    else
    {
        derData.append(((char*)derItem.data), derItem.len);
        conversionSucceeded = TRUE;
    }
#else
    Os::Logger::instance().log(FAC_SIP, PRI_ERR,
        "SmimeBody::convertPemToDer implemented with NSS and OpenSSL disabled");
#endif

    return(conversionSucceeded);
}
Esempio n. 6
0
int oauth_verify_rsa_sha1 (const char *m, const char *c, const char *sig) {
  PK11SlotInfo      *slot = NULL;
  SECKEYPublicKey   *pkey = NULL;
  CERTCertificate   *cert = NULL;
  SECItem            signature;
  SECStatus          s;
  SECItem            der;
  int                rv=0;

  char *key = oauth_strip_pkcs(c, NS_CERT_HEADER, NS_CERT_TRAILER); 
  if (!key) return 0;

  oauth_init_nss();

  s = ATOB_ConvertAsciiToItem(&signature, (char*) sig); // XXX cast (const char*) -> (char*)
  if (s != SECSuccess) goto looser;
  slot = PK11_GetInternalKeySlot();
  if (!slot) goto looser;
  s = ATOB_ConvertAsciiToItem(&der, key);
  if (s != SECSuccess) goto looser;
  cert = __CERT_DecodeDERCertificate(&der, PR_TRUE, NULL);
  SECITEM_FreeItem(&der, PR_FALSE); 
  if (!cert) goto looser;
  pkey = CERT_ExtractPublicKey(cert);
  if (!pkey) goto looser;
  if (pkey->keyType != rsaKey) goto looser;

  s = VFY_VerifyData((unsigned char*) m, strlen(m), pkey, &signature, SEC_OID_ISO_SHA1_WITH_RSA_SIGNATURE, NULL);
  if (s == SECSuccess) rv=1;
#if 0
  else if (PR_GetError()!= SEC_ERROR_BAD_SIGNATURE) rv=-1;
#endif

looser:
  if (pkey) SECKEY_DestroyPublicKey(pkey);
  if (slot) PK11_FreeSlot(slot);
  free(key);
  return rv;
}
Esempio n. 7
0
CERTCertificate *
CERT_ConvertAndDecodeCertificate(char *certstr)
{
    CERTCertificate *cert;
    SECStatus rv;
    SECItem der;

    rv = ATOB_ConvertAsciiToItem(&der, certstr);
    if (rv != SECSuccess)
	return NULL;

    cert = CERT_NewTempCertificate(CERT_GetDefaultCertDB(), 
                                   &der, NULL, PR_FALSE, PR_TRUE);

    PORT_Free(der.data);
    return cert;
}
Esempio n. 8
0
/* Modified from NSS source */
SECStatus
SECU_ReadDER(SECItem *der, std::string data)
{
  SECStatus rv;

  /* First convert ascii to binary */
  //SECItem filedata;
  char *asc, *body;

  /* Read in ascii data */
  asc = const_cast<char*>(data.data());
  if (!asc) {
    fprintf(stderr, "unable to read data from input file\n");
    return SECFailure;
  }

  /* check for headers and trailers and remove them */
  if ((body = strstr(asc, "-----BEGIN")) != NULL) {
    char *trailer = NULL;
    asc = body;
    body = PORT_Strchr(body, '\n');
    if (!body)
      body = PORT_Strchr(asc, '\r'); /* maybe this is a MAC file */
    if (body)
      trailer = strstr(++body, "-----END");
    if (trailer != NULL) {
      *trailer = '\0';
    } else {
      fprintf(stderr, "input has header but no trailer\n");
      return SECFailure;
    }
  } else {
    body = asc;
  }

  /* Convert to binary */
  rv = ATOB_ConvertAsciiToItem(der, body);
  if (rv) {
    return SECFailure;
  }
  return SECSuccess;
}
static void
loadTestEVInfos()
{
  if (!testEVInfos)
    return;

  testEVInfos->Clear();

  char *env_val = getenv("ENABLE_TEST_EV_ROOTS_FILE");
  if (!env_val)
    return;
    
  int enabled_val = atoi(env_val);
  if (!enabled_val)
    return;

  nsCOMPtr<nsIFile> aFile;
  NS_GetSpecialDirectory(NS_APP_USER_PROFILE_50_DIR, getter_AddRefs(aFile));
  if (!aFile)
    return;

  aFile->AppendNative(NS_LITERAL_CSTRING(kTestEVRootsFileName));

  nsresult rv;
  nsCOMPtr<nsIInputStream> fileInputStream;
  rv = NS_NewLocalFileInputStream(getter_AddRefs(fileInputStream), aFile);
  if (NS_FAILED(rv))
    return;

  nsCOMPtr<nsILineInputStream> lineInputStream = do_QueryInterface(fileInputStream, &rv);
  if (NS_FAILED(rv))
    return;

  nsCAutoString buffer;
  PRBool isMore = PR_TRUE;

  /* file format
   *
   * file format must be strictly followed
   * strings in file must be UTF-8
   * each record consists of multiple lines
   * each line consists of a descriptor, a single space, and the data
   * the descriptors are:
   *   1_fingerprint (in format XX:XX:XX:...)
   *   2_readable_oid (treated as a comment)
   * the input file must strictly follow this order
   * the input file may contain 0, 1 or many records
   * completely empty lines are ignored
   * lines that start with the # char are ignored
   */

  int line_counter = 0;
  PRBool found_error = PR_FALSE;

  enum { 
    pos_fingerprint, pos_readable_oid, pos_issuer, pos_serial
  } reader_position = pos_fingerprint;

  nsCString fingerprint, readable_oid, issuer, serial;

  while (isMore && NS_SUCCEEDED(lineInputStream->ReadLine(buffer, &isMore))) {
    ++line_counter;
    if (buffer.IsEmpty() || buffer.First() == '#') {
      continue;
    }

    PRInt32 seperatorIndex = buffer.FindChar(' ', 0);
    if (seperatorIndex == 0) {
      found_error = PR_TRUE;
      break;
    }

    const nsASingleFragmentCString &descriptor = Substring(buffer, 0, seperatorIndex);
    const nsASingleFragmentCString &data = 
            Substring(buffer, seperatorIndex + 1, 
                      buffer.Length() - seperatorIndex + 1);

    if (reader_position == pos_fingerprint &&
        descriptor.EqualsLiteral(("1_fingerprint"))) {
      fingerprint = data;
      reader_position = pos_readable_oid;
      continue;
    }
    else if (reader_position == pos_readable_oid &&
        descriptor.EqualsLiteral(("2_readable_oid"))) {
      readable_oid = data;
      reader_position = pos_issuer;
      continue;
    }
    else if (reader_position == pos_issuer &&
        descriptor.EqualsLiteral(("3_issuer"))) {
      issuer = data;
      reader_position = pos_serial;
      continue;
    }
    else if (reader_position == pos_serial &&
        descriptor.EqualsLiteral(("4_serial"))) {
      serial = data;
      reader_position = pos_fingerprint;
    }
    else {
      found_error = PR_TRUE;
      break;
    }

    nsMyTrustedEVInfoClass *temp_ev = new nsMyTrustedEVInfoClass;
    if (!temp_ev)
      return;

    temp_ev->ev_root_sha1_fingerprint = strdup(fingerprint.get());
    temp_ev->oid_name = strdup(readable_oid.get());
    temp_ev->dotted_oid = strdup(readable_oid.get());
    temp_ev->issuer_base64 = strdup(issuer.get());
    temp_ev->serial_base64 = strdup(serial.get());

    SECStatus rv;
    CERTIssuerAndSN ias;

    rv = ATOB_ConvertAsciiToItem(&ias.derIssuer, const_cast<char*>(temp_ev->issuer_base64));
    NS_ASSERTION(rv==SECSuccess, "error converting ascii to binary.");
    rv = ATOB_ConvertAsciiToItem(&ias.serialNumber, const_cast<char*>(temp_ev->serial_base64));
    NS_ASSERTION(rv==SECSuccess, "error converting ascii to binary.");

    temp_ev->cert = CERT_FindCertByIssuerAndSN(nsnull, &ias);
    NS_ASSERTION(temp_ev->cert, "Could not find EV root in NSS storage");

    if (!temp_ev->cert)
      return;

    nsNSSCertificate c(temp_ev->cert);
    nsAutoString fingerprint;
    c.GetSha1Fingerprint(fingerprint);

    NS_ConvertASCIItoUTF16 sha1(temp_ev->ev_root_sha1_fingerprint);

    if (sha1 != fingerprint) {
      NS_ASSERTION(sha1 == fingerprint, "found EV root with unexpected SHA1 mismatch");
      CERT_DestroyCertificate(temp_ev->cert);
      temp_ev->cert = nsnull;
      return;
    }

    SECItem ev_oid_item;
    ev_oid_item.data = nsnull;
    ev_oid_item.len = 0;
    SECStatus srv = SEC_StringToOID(nsnull, &ev_oid_item,
                                    readable_oid.get(), readable_oid.Length());
    if (srv != SECSuccess) {
      delete temp_ev;
      found_error = PR_TRUE;
      break;
    }

    temp_ev->oid_tag = register_oid(&ev_oid_item, temp_ev->oid_name);
    SECITEM_FreeItem(&ev_oid_item, PR_FALSE);

    testEVInfos->AppendElement(temp_ev);
  }

  if (found_error) {
    fprintf(stderr, "invalid line %d in test_ev_roots file\n", line_counter);
  }
}
Esempio n. 10
0
static PRStatus
IdentityInfoInit()
{
  for (size_t iEV = 0; iEV < PR_ARRAY_SIZE(myTrustedEVInfos); ++iEV) {
    nsMyTrustedEVInfo& entry = myTrustedEVInfos[iEV];

    SECStatus rv;
    CERTIssuerAndSN ias;

    rv = ATOB_ConvertAsciiToItem(&ias.derIssuer, const_cast<char*>(entry.issuer_base64));
    PR_ASSERT(rv == SECSuccess);
    if (rv != SECSuccess) {
      return PR_FAILURE;
    }
    rv = ATOB_ConvertAsciiToItem(&ias.serialNumber,
                                 const_cast<char*>(entry.serial_base64));
    PR_ASSERT(rv == SECSuccess);
    if (rv != SECSuccess) {
      SECITEM_FreeItem(&ias.derIssuer, false);
      return PR_FAILURE;
    }

    ias.serialNumber.type = siUnsignedInteger;

    entry.cert = CERT_FindCertByIssuerAndSN(nullptr, &ias);

    SECITEM_FreeItem(&ias.derIssuer, false);
    SECITEM_FreeItem(&ias.serialNumber, false);

    // If an entry is missing in the NSS root database, it may be because the
    // root database is out of sync with what we expect (e.g. a different
    // version of system NSS is installed). We will just silently avoid
    // treating that root cert as EV.
    if (!entry.cert) {
#ifdef DEBUG
      // The debug CA info is at position 0, and is NOT on the NSS root db
      if (iEV == 0) {
        continue;
      }
#endif
      PR_NOT_REACHED("Could not find EV root in NSS storage");
      continue;
    }

    unsigned char certFingerprint[20];
    rv = PK11_HashBuf(SEC_OID_SHA1, certFingerprint,
                      entry.cert->derCert.data, entry.cert->derCert.len);
    PR_ASSERT(rv == SECSuccess);
    if (rv == SECSuccess) {
      bool same = !memcmp(certFingerprint, entry.ev_root_sha1_fingerprint, 20);
      PR_ASSERT(same);
      if (same) {

        SECItem ev_oid_item;
        ev_oid_item.data = nullptr;
        ev_oid_item.len = 0;
        rv = SEC_StringToOID(nullptr, &ev_oid_item, entry.dotted_oid, 0);
        PR_ASSERT(rv == SECSuccess);
        if (rv == SECSuccess) {
          entry.oid_tag = register_oid(&ev_oid_item, entry.oid_name);
          if (entry.oid_tag == SEC_OID_UNKNOWN) {
            rv = SECFailure;
          }
          SECITEM_FreeItem(&ev_oid_item, false);
        }
      } else {
        PR_SetError(SEC_ERROR_BAD_DATA, 0);
        rv = SECFailure;
      }
    }

    if (rv != SECSuccess) {
      CERT_DestroyCertificate(entry.cert);
      entry.cert = nullptr;
      entry.oid_tag = SEC_OID_UNKNOWN;
      return PR_FAILURE;
    }
  }

  return PR_SUCCESS;
}
Esempio n. 11
0
File: nss.c Progetto: 0w/moai-dev
static int nss_load_crl(const char* crlfilename, PRBool ascii)
{
  PRFileDesc *infile;
  PRStatus    prstat;
  PRFileInfo  info;
  PRInt32     nb;
  int rv;
  SECItem crlDER;
  CERTSignedCrl *crl=NULL;
  PK11SlotInfo *slot=NULL;

  infile = PR_Open(crlfilename,PR_RDONLY,0);
  if (!infile) {
    return 0;
  }
  crlDER.data = NULL;
  prstat = PR_GetOpenFileInfo(infile,&info);
  if (prstat!=PR_SUCCESS)
    return 0;
  if (ascii) {
    SECItem filedata;
    char *asc,*body;
    filedata.data = NULL;
    if (!SECITEM_AllocItem(NULL,&filedata,info.size))
      return 0;
    nb = PR_Read(infile,filedata.data,info.size);
    if (nb!=info.size)
      return 0;
    asc = (char*)filedata.data;
    if (!asc)
      return 0;

    body=strstr(asc,"-----BEGIN");
    if (body != NULL) {
      char *trailer=NULL;
      asc = body;
      body = PORT_Strchr(asc,'\n');
      if (!body)
        body = PORT_Strchr(asc,'\r');
      if (body)
        trailer = strstr(++body,"-----END");
      if (trailer!=NULL)
        *trailer='\0';
      else
        return 0;
    }
    else {
      body = asc;
    }
    rv = ATOB_ConvertAsciiToItem(&crlDER,body);
    PORT_Free(filedata.data);
    if (rv)
      return 0;
  }
  else {
    if (!SECITEM_AllocItem(NULL,&crlDER,info.size))
      return 0;
    nb = PR_Read(infile,crlDER.data,info.size);
    if (nb!=info.size)
      return 0;
  }

  slot = PK11_GetInternalKeySlot();
  crl  = PK11_ImportCRL(slot,&crlDER,
                        NULL,SEC_CRL_TYPE,
                        NULL,CRL_IMPORT_DEFAULT_OPTIONS,
                        NULL,(CRL_DECODE_DEFAULT_OPTIONS|
                              CRL_DECODE_DONT_COPY_DER));
  if (slot) PK11_FreeSlot(slot);
  if (!crl) return 0;
  SEC_DestroyCrl(crl);
  return 1;
}
pubkey_error_code pubkey_from_base64 (const char *pubkstr, pubkey_data **dst) {
  /* This is the ugly part. Inspired by https://developer.mozilla.org/en-US/docs/Mozilla/Projects/NSS/nss_sample_code/NSS_Sample_Code_sample5 */

  if (!NSS_IsInitialized ()) {
    if (SECSuccess != NSS_NoDB_Init (".")) {
      return pubkey_ec_nss_internal;
    }
  }

  PK11SlotInfo *slot = PK11_GetInternalKeySlot ();
  if (slot == NULL) {
    return pubkey_ec_nss_internal;
  }

  SECItem der;
  der.data = NULL;
  der.len = 0;
  der.type = 0;
  if (SECSuccess != ATOB_ConvertAsciiToItem (&der, pubkstr)) {
    PK11_FreeSlot(slot);
    return pubkey_ec_nss_internal;
  }

  SECKEYPublicKey *pubkey = my_SECKEY_DecodeDERPublicKey (&der);
  pubkey_error_code ec = pubkey_ec_ok;
  if (!pubkey) {
    ec = pubkey_ec_nss_internal;
  }
  SECITEM_FreeItem (&der, 0);
//  if (!ec && rsaKey != pubkey->keyType) {
//    ec = pubkey_ec_nss_internal;
//  }
  if (!ec && (siUnsignedInteger != pubkey->u.rsa.modulus.type)) {
    ec = pubkey_ec_nss_internal;
  }
  if (!ec && (siUnsignedInteger != pubkey->u.rsa.publicExponent.type)) {
    ec = pubkey_ec_nss_internal;
  }
  if (!ec && (PUBKEY_USE_MAX_MOD_LEN < pubkey->u.rsa.modulus.len)) {
    ec = pubkey_ec_too_large;
  }
  if (!ec && (4 < pubkey->u.rsa.publicExponent.len)) {
    ec = pubkey_ec_too_large;
  }

  *dst = NULL;
  if (!ec) {
    *dst = malloc (sizeof (pubkey_data));
    if (!*dst) {
      ec = pubkey_ec_nss_internal; // Lie.
    }
  }

  if (!ec) {
    assert(*dst);
    (*dst)->exponent = 0;
    const unsigned int e_len = pubkey->u.rsa.publicExponent.len;
    for (unsigned int i = 0; i < e_len; ++i) {
      (*dst)->exponent <<= 8;
      (*dst)->exponent |= pubkey->u.rsa.publicExponent.data[i];
    }
    const unsigned int m_len = pubkey->u.rsa.modulus.len;
    assert (m_len <= PUBKEY_USE_MAX_MOD_LEN);
    (*dst)->modulus_length = m_len;
    memcpy ((*dst)->modulus, pubkey->u.rsa.modulus.data, m_len);
  }

  if (pubkey) {
    SECKEY_DestroyPublicKey (pubkey);
  }
  assert (slot);
  PK11_FreeSlot (slot);

  return ec;
}