/* * check if any crls are about to expire */ void check_crls(void) { x509crl_t *crl; lock_crl_list("check_crls"); crl = x509crls; while (crl != NULL) { deltatime_t time_left = realtimediff(crl->nextUpdate, realnow()); char buf[ASN1_BUF_LEN]; DBG(DBG_X509, { dntoa(buf, ASN1_BUF_LEN, crl->issuer); DBG_log("issuer: '%s'", buf); if (crl->authKeyID.ptr != NULL) { datatot(crl->authKeyID.ptr, crl->authKeyID.len, ':', buf, ASN1_BUF_LEN); DBG_log("authkey: %s", buf); } DBG_log("%ld seconds left", (long)deltasecs(time_left)); }); if (deltaless(time_left, deltatimescale(2, 1, crl_check_interval))) add_crl_fetch_request(crl->issuer, crl->distributionPoints); crl = crl->next; }
/* * we write out an empty record with the right WHACK magic. * this should permit a later mechanism to figure out the * endianess of the file, since we will get records from * other systems for analysis eventually. */ static bool openwhackrecordfile(char *file) { char when[256]; char FQDN[HOST_NAME_MAX + 1]; u_int32_t magic; struct tm tm1, *tm; realtime_t n = realnow(); strcpy(FQDN, "unknown host"); gethostname(FQDN, sizeof(FQDN)); strncpy(whackrecordname, file, sizeof(whackrecordname)-1); whackrecordname[sizeof(whackrecordname)-1] = '\0'; /* ensure NUL termination */ whackrecordfile = fopen(whackrecordname, "w"); if (whackrecordfile == NULL) { libreswan_log("Failed to open whack record file: '%s'", whackrecordname); return FALSE; } tm = localtime_r(&n.real_secs, &tm1); strftime(when, sizeof(when), "%F %T", tm); fprintf(whackrecordfile, "#!-pluto-whack-file- recorded on %s on %s", FQDN, when); magic = WHACK_BASIC_MAGIC; writewhackrecord((char *)&magic, sizeof(magic)); DBG(DBG_CONTROL, DBG_log("started recording whack messages to %s", whackrecordname)); return TRUE; }
static void prettynow(char *buf, size_t buflen, const char *fmt) { realtime_t n = realnow(); struct tm tm1; struct tm *t = localtime_r(&n.real_secs, &tm1); /* the cast suppresses a warning: <http://gcc.gnu.org/bugzilla/show_bug.cgi?id=39438> */ ((size_t (*)(char *, size_t, const char *, const struct tm *))strftime)(buf, buflen, fmt, t); }
void daily_log_event(void) { struct tm tm1, *ltime; time_t interval; realtime_t n = realnow(); /* schedule event for midnight, local time */ tzset(); ltime = localtime_r(&n.real_secs, &tm1); interval = secs_per_day - (ltime->tm_sec + ltime->tm_min * secs_per_minute + ltime->tm_hour * secs_per_hour); /* this might happen during a leap second */ if (interval <= 0) interval = secs_per_day; event_schedule(EVENT_LOG_DAILY, interval, NULL); daily_log_reset(); }
/* * 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; }
/* * verify if a cert hasn't been revoked by a crl */ static bool verify_by_crl(/*const*/ x509cert_t *cert, bool strict, realtime_t *until) { x509crl_t *crl; char ibuf[ASN1_BUF_LEN], cbuf[ASN1_BUF_LEN]; lock_crl_list("verify_by_crl"); crl = get_x509crl(cert->issuer, cert->authKeySerialNumber, cert->authKeyID); dntoa(ibuf, ASN1_BUF_LEN, cert->issuer); if (crl == NULL) { unlock_crl_list("verify_by_crl"); libreswan_log("no crl from issuer \"%s\" found (strict=%s)", ibuf, strict ? "yes" : "no"); #if defined(LIBCURL) || defined(LDAP_VER) if (cert->crlDistributionPoints != NULL) { add_crl_fetch_request(cert->issuer, cert->crlDistributionPoints); wake_fetch_thread("verify_by_crl"); } #endif if (strict) return FALSE; } else { x509cert_t *issuer_cert; bool valid; DBG(DBG_X509, DBG_log("issuer crl \"%s\" found", ibuf)); #if defined(LIBCURL) || defined(LDAP_VER) add_distribution_points(cert->crlDistributionPoints, &crl->distributionPoints); #endif lock_authcert_list("verify_by_crl"); issuer_cert = get_authcert(crl->issuer, crl->authKeySerialNumber, crl->authKeyID, AUTH_CA); dntoa(cbuf, ASN1_BUF_LEN, crl->issuer); valid = check_signature(crl->tbsCertList, crl->signature, crl->algorithm, issuer_cert); unlock_authcert_list("verify_by_crl"); if (valid) { bool revoked_crl, expired_crl; DBG(DBG_X509, DBG_log("valid crl signature on \"%s\"", cbuf)); /* with strict crl policy the public key must have the same * lifetime as the crl */ if (strict && realbefore(crl->nextUpdate, *until)) *until = crl->nextUpdate; /* has the certificate been revoked? */ revoked_crl = x509_check_revocation(crl, cert->serialNumber); /* is the crl still valid? */ expired_crl = realbefore(crl->nextUpdate, realnow()); unlock_crl_list("verify_by_crl"); if (expired_crl) { char tbuf[REALTIMETOA_BUF]; libreswan_log( "crl update for \"%s\" is overdue since %s", cbuf, realtimetoa(crl->nextUpdate, TRUE, tbuf, sizeof(tbuf))); #if defined(LIBCURL) || defined(LDAP_VER) /* try to fetch a crl update */ if (cert->crlDistributionPoints != NULL) { add_crl_fetch_request(cert->issuer, cert->crlDistributionPoints); wake_fetch_thread("verify_by_crl"); } #endif } else { DBG(DBG_X509, DBG_log("crl is \"%s\" valid", cbuf)); } if (revoked_crl || (strict && expired_crl)) { /* remove any cached public keys */ remove_x509_public_key(cert); return FALSE; } } else { unlock_crl_list("verify_by_crl"); libreswan_log("invalid crl signature on \"%s\"", cbuf); if (strict) return FALSE; } } return TRUE; }
/* * Insert X.509 CRL into chained list */ bool insert_crl(chunk_t blob, chunk_t crl_uri) { x509crl_t *crl = alloc_thing(x509crl_t, "x509crl"); *crl = empty_x509crl; if (parse_x509crl(blob, 0, crl)) { x509cert_t *issuer_cert; x509crl_t *oldcrl; bool valid_sig; generalName_t *gn; /* add distribution point */ gn = alloc_thing(generalName_t, "generalName"); gn->kind = GN_URI; gn->name = crl_uri; gn->next = crl->distributionPoints; crl->distributionPoints = gn; lock_authcert_list("insert_crl"); /* get the issuer cacert */ issuer_cert = get_authcert(crl->issuer, crl->authKeySerialNumber, crl->authKeyID, AUTH_CA); if (issuer_cert == NULL) { chunk_t *n = &crl->distributionPoints->name; loglog(RC_LOG_SERIOUS, "CRL rejected: crl issuer cacert not found for %.*s", (int)n->len, (char *)n->ptr); free_crl(crl); unlock_authcert_list("insert_crl"); return FALSE; } DBG(DBG_X509, DBG_log("crl issuer cacert found")); /* check the issuer's signature of the crl */ valid_sig = check_signature(crl->tbsCertList, crl->signature, crl->algorithm, issuer_cert); unlock_authcert_list("insert_crl"); if (!valid_sig) { free_crl(crl); return FALSE; } DBG(DBG_X509, DBG_log("valid crl signature")); lock_crl_list("insert_crl"); oldcrl = get_x509crl(crl->issuer, crl->authKeySerialNumber, crl->authKeyID); if (oldcrl != NULL) { if (realbefore(oldcrl->thisUpdate, crl->thisUpdate)) { /* old CRL is older than new CRL: replace */ #if defined(LIBCURL) || defined(LDAP_VER) /* keep any known CRL distribution points */ add_distribution_points( oldcrl->distributionPoints, &crl->distributionPoints); #endif /* now delete the old CRL */ free_first_crl(); DBG(DBG_X509, DBG_log("thisUpdate is newer - existing crl deleted")); } else { /* old CRL is not older than new CRL: keep old one */ unlock_crl_list("insert_crls"); DBG(DBG_X509, DBG_log("thisUpdate is not newer - existing crl not replaced")); free_crl(crl); /* * is the fetched crl valid? * now + 2 * crl_check_interval < oldcrl->nextUpdate */ return realbefore(realtimesum(realnow(), deltatimescale(2, 1, crl_check_interval)), oldcrl->nextUpdate); } } /* insert new CRL */ crl->next = x509crls; x509crls = crl; unlock_crl_list("insert_crl"); /* * is the new crl valid? * now + 2 * crl_check_interval < crl->nextUpdate */ return realbefore(realtimesum(realnow(), deltatimescale(2, 1, crl_check_interval)), crl->nextUpdate); } else { loglog(RC_LOG_SERIOUS, " error in X.509 crl %s", (char *)crl_uri.ptr); free_crl(crl); return FALSE; } }
/* * 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, char *configdir, char *password) { SECStatus rv; PK11RSAGenParams rsaparams = { nbits, (long) E }; secuPWData pwdata = { PW_NONE, NULL }; PK11SlotInfo *slot = NULL; SECKEYPrivateKey *privkey = NULL; SECKEYPublicKey *pubkey = NULL; realtime_t now = realnow(); if (password == NULL) { pwdata.source = PW_NONE; } else { /* check if passwd == configdir/nsspassword */ size_t cdl = strlen(configdir); size_t pwl = strlen(password); static const char suf[] = "/nsspassword"; if (pwl == cdl + sizeof(suf) - 1 && memeq(password, configdir, cdl) && memeq(password + cdl, suf, sizeof(suf))) pwdata.source = PW_FROMFILE; else pwdata.source = PW_PLAINTEXT; } pwdata.data = password; lsw_nss_buf_t err; if (!lsw_nss_setup(configdir, FALSE/*rw*/, GetModulePassword, err)) { fprintf(stderr, "%s: %s\n", me, 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 if (PK11_IsFIPS() && password == NULL) { fprintf(stderr, "%s: On FIPS mode a password is required\n", me); exit(1); } /* Good for now but someone may want to use a hardware token */ slot = PK11_GetInternalKeySlot(); /* In which case this may be better */ /* slot = PK11_GetBestSlot(CKM_RSA_PKCS_KEY_PAIR_GEN, password ? &pwdata : NULL); */ /* or the user may specify the name of a token. */ #if 0 if (PK11_IsFIPS() || !PK11_IsInternal(slot)) { rv = PK11_Authenticate(slot, PR_FALSE, &pwdata); if (rv != SECSuccess) { fprintf(stderr, "%s: could not authenticate to token '%s'\n", me, PK11_GetTokenName(slot)); return; } } #endif /* 0 */ /* Do some random-number initialization. */ UpdateNSS_RNG(seedbits); /* Log in to the token */ if (password != NULL) { rv = PK11_Authenticate(slot, PR_FALSE, &pwdata); if (rv != SECSuccess) { fprintf(stderr, "%s: could not authenticate to token '%s'\n", me, PK11_GetTokenName(slot)); return; } } privkey = PK11_GenerateKeyPair(slot, CKM_RSA_PKCS_KEY_PAIR_GEN, &rsaparams, &pubkey, PR_TRUE, password != NULL? PR_TRUE : PR_FALSE, &pwdata); /* inTheToken, isSensitive, passwordCallbackFunction */ if (privkey == NULL) { fprintf(stderr, "%s: key pair generation failed: \"%d\"\n", me, 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", me); 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 */ report("output...\n"); /* deliberate extra newline */ printf("\t# RSA %d bits %s %s", nbits, outputhostname, ctime(&now.real_secs)); /* ctime provides \n */ printf("\t# for signatures only, UNSAFE FOR ENCRYPTION\n"); printf("\t#ckaid=%s\n", hex_ckaid); /* RFC2537/RFC3110-ish format */ { char *bundle = base64_bundle(E, public_modulus); printf("\t#pubkey=%s\n", bundle); pfree(bundle); } 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_NSS_CLEANUP); } /* * getrandom - get some random bytes from /dev/random (or wherever) * NOTE: This is only used for additional seeding of the NSS RNG */ void getrandom(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", me, device, strerror(errno)); exit(1); } ndone = 0; if (verbose) { fprintf(stderr, "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", me, device, strerror(errno)); exit(1); } if (got == 0) { fprintf(stderr, "%s: eof on %s!?!\n", me, 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", me); exit(1); } if (n > sizeof(convbuf)) { fprintf(stderr, "%s: can't-happen convert overflow (need %d)\n", me, (int) n); exit(1); } return convbuf; } /* - report - report progress, if indicated */ void report(msg) char *msg; { if (!verbose) return; fprintf(stderr, "%s\n", msg); }
/* * 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, char *configdir, char *password) { SECStatus rv; PK11RSAGenParams rsaparams = { nbits, (long) E }; secuPWData pwdata = { PW_NONE, NULL }; PK11SlotInfo *slot = NULL; SECKEYPrivateKey *privkey = NULL; SECKEYPublicKey *pubkey = NULL; unsigned char *bundp = NULL; mpz_t n; mpz_t e; size_t bs; char n_str[3 + MAXBITS / 4 + 1]; realtime_t now = realnow(); mpz_init(n); mpz_init(e); if (password == NULL) { pwdata.source = PW_NONE; } else { /* check if passwd == configdir/nsspassword */ size_t cdl = strlen(configdir); size_t pwl = strlen(password); static const char suf[] = "/nsspassword"; if (pwl == cdl + sizeof(suf) - 1 && memeq(password, configdir, cdl) && memeq(password + cdl, suf, sizeof(suf))) pwdata.source = PW_FROMFILE; else pwdata.source = PW_PLAINTEXT; } pwdata.data = password; PR_Init(PR_USER_THREAD, PR_PRIORITY_NORMAL, 1); rv = NSS_InitReadWrite(configdir); if (rv != SECSuccess) { fprintf(stderr, "%s: NSS_InitReadWrite(%s) returned %d\n", me, configdir, PR_GetError()); exit(1); } #ifdef FIPS_CHECK if (PK11_IsFIPS() && !FIPSCHECK_verify(NULL, NULL)) { fprintf(stderr, "FIPS HMAC integrity verification test failed.\n"); exit(1); } #endif if (PK11_IsFIPS() && !password) { fprintf(stderr, "%s: On FIPS mode a password is required\n", me); exit(1); } PK11_SetPasswordFunc(GetModulePassword); /* Good for now but someone may want to use a hardware token */ slot = PK11_GetInternalKeySlot(); /* In which case this may be better */ /* slot = PK11_GetBestSlot(CKM_RSA_PKCS_KEY_PAIR_GEN, password ? &pwdata : NULL); */ /* or the user may specify the name of a token. */ #if 0 if (PK11_IsFIPS() || !PK11_IsInternal(slot)) { rv = PK11_Authenticate(slot, PR_FALSE, &pwdata); if (rv != SECSuccess) { fprintf(stderr, "%s: could not authenticate to token '%s'\n", me, PK11_GetTokenName(slot)); return; } } #endif /* 0 */ /* Do some random-number initialization. */ UpdateNSS_RNG(); /* Log in to the token */ if (password) { rv = PK11_Authenticate(slot, PR_FALSE, &pwdata); if (rv != SECSuccess) { fprintf(stderr, "%s: could not authenticate to token '%s'\n", me, PK11_GetTokenName(slot)); return; } } privkey = PK11_GenerateKeyPair(slot, CKM_RSA_PKCS_KEY_PAIR_GEN, &rsaparams, &pubkey, PR_TRUE, password ? PR_TRUE : PR_FALSE, &pwdata); /* inTheToken, isSensitive, passwordCallbackFunction */ if (!privkey) { fprintf(stderr, "%s: key pair generation failed: \"%d\"\n", me, PORT_GetError()); return; } /*privkey->wincx = &pwdata;*/ PORT_Assert(pubkey != NULL); fprintf(stderr, "Generated RSA key pair using the NSS database\n"); SECItemToHex(getModulus(pubkey), n_str); assert(!mpz_set_str(n, n_str, 16)); /* and the output */ report("output...\n"); /* deliberate extra newline */ printf("\t# RSA %d bits %s %s", nbits, outputhostname, ctime(&now.real_secs)); /* ctime provides \n */ printf("\t# for signatures only, UNSAFE FOR ENCRYPTION\n"); bundp = bundle(E, n, &bs); printf("\t#pubkey=%s\n", conv(bundp, bs, 's')); /* RFC2537ish format */ printf("\tModulus: %s\n", hexOut(getModulus(pubkey))); printf("\tPublicExponent: %s\n", hexOut(getPublicExponent(pubkey))); SECItem *ckaID = PK11_MakeIDFromPubKey(getModulus(pubkey)); if (ckaID != NULL) { printf("\t# everything after this point is CKA_ID in hex format - not the real values \n"); printf("\tPrivateExponent: %s\n", hexOut(ckaID)); printf("\tPrime1: %s\n", hexOut(ckaID)); printf("\tPrime2: %s\n", hexOut(ckaID)); printf("\tExponent1: %s\n", hexOut(ckaID)); printf("\tExponent2: %s\n", hexOut(ckaID)); printf("\tCoefficient: %s\n", hexOut(ckaID)); printf("\tCKAIDNSS: %s\n", hexOut(ckaID)); SECITEM_FreeItem(ckaID, PR_TRUE); } if (privkey) SECKEY_DestroyPrivateKey(privkey); if (pubkey) SECKEY_DestroyPublicKey(pubkey); (void) NSS_Shutdown(); (void) PR_Cleanup(); }