/* * bundle - bundle e and n into an RFC2537-format chunk_t */ static char *base64_bundle(int e, chunk_t modulus) { /* * Pack the single-byte exponent into a byte array. */ assert(e <= 255); u_char exponent_byte = 1; chunk_t exponent = { .ptr = &exponent_byte, .len = 1, }; /* * Create the resource record. */ char *bundle; err_t err = rsa_pubkey_to_base64(exponent, modulus, &bundle); if (err) { fprintf(stderr, "%s: can't-happen bundle convert error `%s'\n", progname, err); exit(1); } return bundle; } /* UpdateRNG - Updates NSS's PRNG with user generated entropy. */ static void UpdateNSS_RNG(int seedbits) { SECStatus rv; int seedbytes = BYTES_FOR_BITS(seedbits); unsigned char *buf = alloc_bytes(seedbytes,"TLA seedmix"); getrandom(seedbytes, buf); rv = PK11_RandomUpdate(buf, seedbytes); assert(rv == SECSuccess); messupn(buf, seedbytes); pfree(buf); }
/* * 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; }