bool lsw_nss_setup(const char *configdir, unsigned setup_flags, PK11PasswordFunc get_password, lsw_nss_buf_t err) { /* * save for cleanup */ flags = setup_flags; /* * According to the manual, not needed, and all parameters are * ignored. Does no harm? */ PR_Init(PR_USER_THREAD, PR_PRIORITY_NORMAL, 1); libreswan_log("Initializing NSS"); if (configdir) { const char sql[] = "sql:"; char *nssdb; if (strncmp(sql, configdir, strlen(sql)) == 0) { nssdb = strdup(configdir); } else { nssdb = alloc_bytes(strlen(configdir) + strlen(sql) + 1, "nssdb"); strcpy(nssdb, sql); strcat(nssdb, configdir); } libreswan_log("Opening NSS database \"%s\" %s", nssdb, (flags & LSW_NSS_READONLY) ? "read-only" : "read-write"); SECStatus rv = NSS_Initialize(nssdb, "", "", SECMOD_DB, (flags & LSW_NSS_READONLY) ? NSS_INIT_READONLY : 0); if (rv != SECSuccess) { snprintf(err, sizeof(lsw_nss_buf_t), "Initialization of NSS with %s database \"%s\" failed (%d)", (flags & LSW_NSS_READONLY) ? "read-only" : "read-write", nssdb, PR_GetError()); pfree(nssdb); return FALSE; } } else { NSS_NoDB_Init("."); } if (PK11_IsFIPS() && get_password == NULL) { snprintf(err, sizeof(lsw_nss_buf_t), "on FIPS mode a password is required"); return FALSE; } if (get_password) { PK11_SetPasswordFunc(get_password); } if (!(flags & LSW_NSS_SKIP_AUTH)) { PK11SlotInfo *slot = lsw_nss_get_authenticated_slot(err); if (slot == NULL) { return FALSE; } PK11_FreeSlot(slot); } return TRUE; }
/* * generate an RSA signature key * * e is fixed at 3, without discussion. That would not be wise if these * keys were to be used for encryption, but for signatures there are some * real speed advantages. * See also: https://www.imperialviolet.org/2012/03/16/rsae.html */ void rsasigkey(int nbits, int seedbits, const struct lsw_conf_options *oco) { PK11RSAGenParams rsaparams = { nbits, (long) F4 }; PK11SlotInfo *slot = NULL; SECKEYPrivateKey *privkey = NULL; SECKEYPublicKey *pubkey = NULL; realtime_t now = realnow(); lsw_nss_buf_t err; if (!lsw_nss_setup(oco->nssdir, 0, lsw_nss_get_password, err)) { fprintf(stderr, "%s: %s\n", progname, err); exit(1); } #ifdef FIPS_CHECK if (PK11_IsFIPS() && !FIPSCHECK_verify(NULL, NULL)) { fprintf(stderr, "FIPS HMAC integrity verification test failed.\n"); exit(1); } #endif /* Good for now but someone may want to use a hardware token */ slot = lsw_nss_get_authenticated_slot(err); if (slot == NULL) { fprintf(stderr, "%s: %s\n", progname, err); lsw_nss_shutdown(); exit(1); } /* Do some random-number initialization. */ UpdateNSS_RNG(seedbits); privkey = PK11_GenerateKeyPair(slot, CKM_RSA_PKCS_KEY_PAIR_GEN, &rsaparams, &pubkey, PR_TRUE, PK11_IsFIPS() ? PR_TRUE : PR_FALSE, lsw_return_nss_password_file_info()); /* inTheToken, isSensitive, passwordCallbackFunction */ if (privkey == NULL) { fprintf(stderr, "%s: key pair generation failed: \"%d\"\n", progname, PORT_GetError()); return; } chunk_t public_modulus = { .ptr = pubkey->u.rsa.modulus.data, .len = pubkey->u.rsa.modulus.len, }; chunk_t public_exponent = { .ptr = pubkey->u.rsa.publicExponent.data, .len = pubkey->u.rsa.publicExponent.len, }; char *hex_ckaid; { SECItem *ckaid = PK11_GetLowLevelKeyIDForPrivateKey(privkey); if (ckaid == NULL) { fprintf(stderr, "%s: 'CKAID' calculation failed\n", progname); exit(1); } hex_ckaid = strdup(conv(ckaid->data, ckaid->len, 16)); SECITEM_FreeItem(ckaid, PR_TRUE); } /*privkey->wincx = &pwdata;*/ PORT_Assert(pubkey != NULL); fprintf(stderr, "Generated RSA key pair with CKAID %s was stored in the NSS database\n", hex_ckaid); /* and the output */ libreswan_log("output...\n"); /* deliberate extra newline */ printf("\t# RSA %d bits %s %s", nbits, outputhostname, ctime(&now.rt.tv_sec)); /* ctime provides \n */ printf("\t# for signatures only, UNSAFE FOR ENCRYPTION\n"); printf("\t#ckaid=%s\n", hex_ckaid); /* RFC2537/RFC3110-ish format */ { char *base64 = NULL; err_t err = rsa_pubkey_to_base64(public_exponent, public_modulus, &base64); if (err) { fprintf(stderr, "%s: unexpected error encoding RSA public key '%s'\n", progname, err); exit(1); } printf("\t#pubkey=%s\n", base64); pfree(base64); } printf("\tModulus: 0x%s\n", conv(public_modulus.ptr, public_modulus.len, 16)); printf("\tPublicExponent: 0x%s\n", conv(public_exponent.ptr, public_exponent.len, 16)); if (hex_ckaid != NULL) free(hex_ckaid); if (privkey != NULL) SECKEY_DestroyPrivateKey(privkey); if (pubkey != NULL) SECKEY_DestroyPublicKey(pubkey); lsw_nss_shutdown(); } /* * lsw_random - get some random bytes from /dev/random (or wherever) * NOTE: This is only used for additional seeding of the NSS RNG */ void lsw_random(size_t nbytes, unsigned char *buf) { size_t ndone; int dev; ssize_t got; dev = open(device, 0); if (dev < 0) { fprintf(stderr, "%s: could not open %s (%s)\n", progname, device, strerror(errno)); exit(1); } ndone = 0; libreswan_log("getting %d random seed bytes for NSS from %s...\n", (int) nbytes * BITS_PER_BYTE, device); while (ndone < nbytes) { got = read(dev, buf + ndone, nbytes - ndone); if (got < 0) { fprintf(stderr, "%s: read error on %s (%s)\n", progname, device, strerror(errno)); exit(1); } if (got == 0) { fprintf(stderr, "%s: eof on %s!?!\n", progname, device); exit(1); } ndone += got; } close(dev); } /* - conv - convert bits to output in specified datatot format * NOTE: result points into a STATIC buffer */ static const char *conv(const unsigned char *bits, size_t nbytes, int format) { static char convbuf[MAXBITS / 4 + 50]; /* enough for hex */ size_t n; n = datatot(bits, nbytes, format, convbuf, sizeof(convbuf)); if (n == 0) { fprintf(stderr, "%s: can't-happen convert error\n", progname); exit(1); } if (n > sizeof(convbuf)) { fprintf(stderr, "%s: can't-happen convert overflow (need %d)\n", progname, (int) n); exit(1); } return convbuf; }
struct private_key_stuff *lsw_nss_foreach_private_key_stuff(secret_eval func, void *uservoid, lsw_nss_buf_t err) { /* * So test for error with "if (err[0]) ..." works. */ err[0] = '\0'; PK11SlotInfo *slot = lsw_nss_get_authenticated_slot(err); if (slot == NULL) { return NULL; } SECKEYPrivateKeyList *list = PK11_ListPrivateKeysInSlot(slot); if (list == NULL) { snprintf(err, sizeof(lsw_nss_buf_t), "no list"); PK11_FreeSlot(slot); return NULL; } int line = 1; struct private_key_stuff *result = NULL; SECKEYPrivateKeyListNode *node; for (node = PRIVKEY_LIST_HEAD(list); !PRIVKEY_LIST_END(node, list); node = PRIVKEY_LIST_NEXT(node)) { if (SECKEY_GetPrivateKeyType(node->key) != rsaKey) { /* only rsa for now */ continue; } struct private_key_stuff pks = { .kind = PPK_RSA, .on_heap = TRUE, }; { SECItem *nss_ckaid = PK11_GetLowLevelKeyIDForPrivateKey(node->key); if (nss_ckaid == NULL) { // fprintf(stderr, "ckaid not found\n"); continue; } const char *err = form_ckaid_nss(nss_ckaid, &pks.u.RSA_private_key.pub.ckaid); SECITEM_FreeItem(nss_ckaid, PR_TRUE); if (err) { // fprintf(stderr, "ckaid not found\n"); continue; } } { SECKEYPublicKey *pubkey = SECKEY_ConvertToPublicKey(node->key); if (pubkey != NULL) { fill_RSA_public_key(&pks.u.RSA_private_key.pub, pubkey); SECKEY_DestroyPublicKey(pubkey); } } /* * Only count private keys that get processed. */ pks.line = line++; int ret = func(NULL, &pks, uservoid); if (ret == 0) { /* * save/return the result. * * XXX: Potential Memory leak. * * lsw_foreach_secret() + lsw_get_pks() * returns an object that must not be freed * BUT lsw_nss_foreach_private_key_stuff() * returns an object that must be freed. * * For moment ignore this - as only caller is * showhostkey.c which quickly exits. */ result = clone_thing(pks, "pks"); break; } freeanyckaid(&pks.u.RSA_private_key.pub.ckaid); freeanychunk(pks.u.RSA_private_key.pub.e); freeanychunk(pks.u.RSA_private_key.pub.n); if (ret < 0) { break; } } SECKEY_DestroyPrivateKeyList(list); PK11_FreeSlot(slot); return result; }