mirror of
https://github.com/rn10950/RetroZilla.git
synced 2024-11-10 18:00:15 +01:00
a572ea8ca3
bug1095307, bug1073330(backout), bug1084986, bug1050069, bug942172, bug1054547, bug532081, bug1096348, bug1058870, bug1093940, bug1102985, bug1112461, bug1094492, bug112029, bug1119983, bug1120685, bug1120691, bug1113632, bug863076, bug1082973, bug1124539, bug1117617, bug1117621, bug1121273, bug753136, bug921684, bug1132818, bug1125375, bug647690, bug1055441, bug1134455, bug975010, bug950369, bug1128367, bug1129573, bug1136095, bug1117897, bug1113453, bug1061725, bug1073330, bug1111901, bug1083900, bug1136095, bug1138820, bug1096741, bug1134548, bug345725, bug950348, bug950344, bug1151037, bug991783, bug1153994
3570 lines
116 KiB
C
3570 lines
116 KiB
C
/* This Source Code Form is subject to the terms of the Mozilla Public
|
|
* License, v. 2.0. If a copy of the MPL was not distributed with this
|
|
* file, You can obtain one at http://mozilla.org/MPL/2.0/. */
|
|
|
|
/*
|
|
** certutil.c
|
|
**
|
|
** utility for managing certificates and the cert database
|
|
**
|
|
*/
|
|
#include <stdio.h>
|
|
#include <string.h>
|
|
#include <stdlib.h>
|
|
|
|
#if defined(WIN32)
|
|
#include "fcntl.h"
|
|
#include "io.h"
|
|
#endif
|
|
|
|
#include "secutil.h"
|
|
|
|
#if defined(XP_UNIX)
|
|
#include <unistd.h>
|
|
#endif
|
|
|
|
#include "nspr.h"
|
|
#include "prtypes.h"
|
|
#include "prtime.h"
|
|
#include "prlong.h"
|
|
|
|
#include "pk11func.h"
|
|
#include "secasn1.h"
|
|
#include "cert.h"
|
|
#include "cryptohi.h"
|
|
#include "secoid.h"
|
|
#include "certdb.h"
|
|
#include "nss.h"
|
|
#include "certutil.h"
|
|
|
|
#define MIN_KEY_BITS 512
|
|
/* MAX_KEY_BITS should agree with MAX_RSA_MODULUS in freebl */
|
|
#define MAX_KEY_BITS 8192
|
|
#define DEFAULT_KEY_BITS 2048
|
|
|
|
#define GEN_BREAK(e) rv=e; break;
|
|
|
|
char *progName;
|
|
|
|
static CERTCertificateRequest *
|
|
GetCertRequest(const SECItem *reqDER)
|
|
{
|
|
CERTCertificateRequest *certReq = NULL;
|
|
CERTSignedData signedData;
|
|
PLArenaPool *arena = NULL;
|
|
SECStatus rv;
|
|
|
|
do {
|
|
arena = PORT_NewArena(DER_DEFAULT_CHUNKSIZE);
|
|
if (arena == NULL) {
|
|
GEN_BREAK (SECFailure);
|
|
}
|
|
|
|
certReq = (CERTCertificateRequest*) PORT_ArenaZAlloc
|
|
(arena, sizeof(CERTCertificateRequest));
|
|
if (!certReq) {
|
|
GEN_BREAK(SECFailure);
|
|
}
|
|
certReq->arena = arena;
|
|
|
|
/* Since cert request is a signed data, must decode to get the inner
|
|
data
|
|
*/
|
|
PORT_Memset(&signedData, 0, sizeof(signedData));
|
|
rv = SEC_ASN1DecodeItem(arena, &signedData,
|
|
SEC_ASN1_GET(CERT_SignedDataTemplate), reqDER);
|
|
if (rv) {
|
|
break;
|
|
}
|
|
rv = SEC_ASN1DecodeItem(arena, certReq,
|
|
SEC_ASN1_GET(CERT_CertificateRequestTemplate), &signedData.data);
|
|
if (rv) {
|
|
break;
|
|
}
|
|
rv = CERT_VerifySignedDataWithPublicKeyInfo(&signedData,
|
|
&certReq->subjectPublicKeyInfo, NULL /* wincx */);
|
|
} while (0);
|
|
|
|
if (rv) {
|
|
SECU_PrintError(progName, "bad certificate request\n");
|
|
if (arena) {
|
|
PORT_FreeArena(arena, PR_FALSE);
|
|
}
|
|
certReq = NULL;
|
|
}
|
|
|
|
return certReq;
|
|
}
|
|
|
|
static SECStatus
|
|
AddCert(PK11SlotInfo *slot, CERTCertDBHandle *handle, char *name, char *trusts,
|
|
const SECItem *certDER, PRBool emailcert, void *pwdata)
|
|
{
|
|
CERTCertTrust *trust = NULL;
|
|
CERTCertificate *cert = NULL;
|
|
SECStatus rv;
|
|
|
|
do {
|
|
/* Read in an ASCII cert and return a CERTCertificate */
|
|
cert = CERT_DecodeCertFromPackage((char *)certDER->data, certDER->len);
|
|
if (!cert) {
|
|
SECU_PrintError(progName, "could not decode certificate");
|
|
GEN_BREAK(SECFailure);
|
|
}
|
|
|
|
/* Create a cert trust */
|
|
trust = (CERTCertTrust *)PORT_ZAlloc(sizeof(CERTCertTrust));
|
|
if (!trust) {
|
|
SECU_PrintError(progName, "unable to allocate cert trust");
|
|
GEN_BREAK(SECFailure);
|
|
}
|
|
|
|
rv = CERT_DecodeTrustString(trust, trusts);
|
|
if (rv) {
|
|
SECU_PrintError(progName, "unable to decode trust string");
|
|
GEN_BREAK(SECFailure);
|
|
}
|
|
|
|
rv = PK11_ImportCert(slot, cert, CK_INVALID_HANDLE, name, PR_FALSE);
|
|
if (rv != SECSuccess) {
|
|
/* sigh, PK11_Import Cert and CERT_ChangeCertTrust should have
|
|
* been coded to take a password arg. */
|
|
if (PORT_GetError() == SEC_ERROR_TOKEN_NOT_LOGGED_IN) {
|
|
rv = PK11_Authenticate(slot, PR_TRUE, pwdata);
|
|
if (rv != SECSuccess) {
|
|
SECU_PrintError(progName,
|
|
"could not authenticate to token %s.",
|
|
PK11_GetTokenName(slot));
|
|
GEN_BREAK(SECFailure);
|
|
}
|
|
rv = PK11_ImportCert(slot, cert, CK_INVALID_HANDLE,
|
|
name, PR_FALSE);
|
|
}
|
|
if (rv != SECSuccess) {
|
|
SECU_PrintError(progName,
|
|
"could not add certificate to token or database");
|
|
GEN_BREAK(SECFailure);
|
|
}
|
|
}
|
|
|
|
rv = CERT_ChangeCertTrust(handle, cert, trust);
|
|
if (rv != SECSuccess) {
|
|
if (PORT_GetError() == SEC_ERROR_TOKEN_NOT_LOGGED_IN) {
|
|
rv = PK11_Authenticate(slot, PR_TRUE, pwdata);
|
|
if (rv != SECSuccess) {
|
|
SECU_PrintError(progName,
|
|
"could not authenticate to token %s.",
|
|
PK11_GetTokenName(slot));
|
|
GEN_BREAK(SECFailure);
|
|
}
|
|
rv = CERT_ChangeCertTrust(handle, cert, trust);
|
|
}
|
|
if (rv != SECSuccess) {
|
|
SECU_PrintError(progName,
|
|
"could not change trust on certificate");
|
|
GEN_BREAK(SECFailure);
|
|
}
|
|
}
|
|
|
|
if ( emailcert ) {
|
|
CERT_SaveSMimeProfile(cert, NULL, pwdata);
|
|
}
|
|
|
|
} while (0);
|
|
|
|
CERT_DestroyCertificate (cert);
|
|
PORT_Free(trust);
|
|
|
|
return rv;
|
|
}
|
|
|
|
static SECStatus
|
|
CertReq(SECKEYPrivateKey *privk, SECKEYPublicKey *pubk, KeyType keyType,
|
|
SECOidTag hashAlgTag, CERTName *subject, char *phone, int ascii,
|
|
const char *emailAddrs, const char *dnsNames,
|
|
certutilExtnList extnList, const char *extGeneric,
|
|
/*out*/ SECItem *result)
|
|
{
|
|
CERTSubjectPublicKeyInfo *spki;
|
|
CERTCertificateRequest *cr;
|
|
SECItem *encoding;
|
|
SECOidTag signAlgTag;
|
|
SECStatus rv;
|
|
PLArenaPool *arena;
|
|
void *extHandle;
|
|
SECItem signedReq = { siBuffer, NULL, 0 };
|
|
|
|
/* Create info about public key */
|
|
spki = SECKEY_CreateSubjectPublicKeyInfo(pubk);
|
|
if (!spki) {
|
|
SECU_PrintError(progName, "unable to create subject public key");
|
|
return SECFailure;
|
|
}
|
|
|
|
/* Generate certificate request */
|
|
cr = CERT_CreateCertificateRequest(subject, spki, NULL);
|
|
SECKEY_DestroySubjectPublicKeyInfo(spki);
|
|
if (!cr) {
|
|
SECU_PrintError(progName, "unable to make certificate request");
|
|
return SECFailure;
|
|
}
|
|
|
|
arena = PORT_NewArena(DER_DEFAULT_CHUNKSIZE);
|
|
if ( !arena ) {
|
|
SECU_PrintError(progName, "out of memory");
|
|
return SECFailure;
|
|
}
|
|
|
|
extHandle = CERT_StartCertificateRequestAttributes(cr);
|
|
if (extHandle == NULL) {
|
|
PORT_FreeArena (arena, PR_FALSE);
|
|
return SECFailure;
|
|
}
|
|
if (AddExtensions(extHandle, emailAddrs, dnsNames, extnList, extGeneric)
|
|
!= SECSuccess) {
|
|
PORT_FreeArena (arena, PR_FALSE);
|
|
return SECFailure;
|
|
}
|
|
CERT_FinishExtensions(extHandle);
|
|
CERT_FinishCertificateRequestAttributes(cr);
|
|
|
|
/* Der encode the request */
|
|
encoding = SEC_ASN1EncodeItem(arena, NULL, cr,
|
|
SEC_ASN1_GET(CERT_CertificateRequestTemplate));
|
|
CERT_DestroyCertificateRequest(cr);
|
|
if (encoding == NULL) {
|
|
PORT_FreeArena (arena, PR_FALSE);
|
|
SECU_PrintError(progName, "der encoding of request failed");
|
|
return SECFailure;
|
|
}
|
|
|
|
/* Sign the request */
|
|
signAlgTag = SEC_GetSignatureAlgorithmOidTag(keyType, hashAlgTag);
|
|
if (signAlgTag == SEC_OID_UNKNOWN) {
|
|
PORT_FreeArena (arena, PR_FALSE);
|
|
SECU_PrintError(progName, "unknown Key or Hash type");
|
|
return SECFailure;
|
|
}
|
|
|
|
rv = SEC_DerSignData(arena, &signedReq, encoding->data, encoding->len,
|
|
privk, signAlgTag);
|
|
if (rv) {
|
|
PORT_FreeArena (arena, PR_FALSE);
|
|
SECU_PrintError(progName, "signing of data failed");
|
|
return SECFailure;
|
|
}
|
|
|
|
/* Encode request in specified format */
|
|
if (ascii) {
|
|
char *obuf;
|
|
char *header, *name, *email, *org, *state, *country;
|
|
|
|
obuf = BTOA_ConvertItemToAscii(&signedReq);
|
|
if (!obuf) {
|
|
goto oom;
|
|
}
|
|
|
|
name = CERT_GetCommonName(subject);
|
|
if (!name) {
|
|
name = PORT_Strdup("(not specified)");
|
|
}
|
|
|
|
if (!phone)
|
|
phone = strdup("(not specified)");
|
|
|
|
email = CERT_GetCertEmailAddress(subject);
|
|
if (!email)
|
|
email = PORT_Strdup("(not specified)");
|
|
|
|
org = CERT_GetOrgName(subject);
|
|
if (!org)
|
|
org = PORT_Strdup("(not specified)");
|
|
|
|
state = CERT_GetStateName(subject);
|
|
if (!state)
|
|
state = PORT_Strdup("(not specified)");
|
|
|
|
country = CERT_GetCountryName(subject);
|
|
if (!country)
|
|
country = PORT_Strdup("(not specified)");
|
|
|
|
header = PR_smprintf(
|
|
"\nCertificate request generated by Netscape certutil\n"
|
|
"Phone: %s\n\n"
|
|
"Common Name: %s\n"
|
|
"Email: %s\n"
|
|
"Organization: %s\n"
|
|
"State: %s\n"
|
|
"Country: %s\n\n"
|
|
"%s\n",
|
|
phone, name, email, org, state, country, NS_CERTREQ_HEADER);
|
|
|
|
PORT_Free(name);
|
|
PORT_Free(email);
|
|
PORT_Free(org);
|
|
PORT_Free(state);
|
|
PORT_Free(country);
|
|
|
|
if (header) {
|
|
char * trailer = PR_smprintf("\n%s\n", NS_CERTREQ_TRAILER);
|
|
if (trailer) {
|
|
PRUint32 headerLen = PL_strlen(header);
|
|
PRUint32 obufLen = PL_strlen(obuf);
|
|
PRUint32 trailerLen = PL_strlen(trailer);
|
|
SECITEM_AllocItem(NULL, result,
|
|
headerLen + obufLen + trailerLen);
|
|
if (result->data) {
|
|
PORT_Memcpy(result->data, header, headerLen);
|
|
PORT_Memcpy(result->data + headerLen, obuf, obufLen);
|
|
PORT_Memcpy(result->data + headerLen + obufLen,
|
|
trailer, trailerLen);
|
|
}
|
|
PR_smprintf_free(trailer);
|
|
}
|
|
PR_smprintf_free(header);
|
|
}
|
|
} else {
|
|
(void) SECITEM_CopyItem(NULL, result, &signedReq);
|
|
}
|
|
|
|
if (!result->data) {
|
|
oom: SECU_PrintError(progName, "out of memory");
|
|
PORT_SetError(SEC_ERROR_NO_MEMORY);
|
|
rv = SECFailure;
|
|
}
|
|
|
|
PORT_FreeArena (arena, PR_FALSE);
|
|
return rv;
|
|
}
|
|
|
|
static SECStatus
|
|
ChangeTrustAttributes(CERTCertDBHandle *handle, PK11SlotInfo *slot,
|
|
char *name, char *trusts, void *pwdata)
|
|
{
|
|
SECStatus rv;
|
|
CERTCertificate *cert;
|
|
CERTCertTrust *trust;
|
|
|
|
cert = CERT_FindCertByNicknameOrEmailAddr(handle, name);
|
|
if (!cert) {
|
|
SECU_PrintError(progName, "could not find certificate named \"%s\"",
|
|
name);
|
|
return SECFailure;
|
|
}
|
|
|
|
trust = (CERTCertTrust *)PORT_ZAlloc(sizeof(CERTCertTrust));
|
|
if (!trust) {
|
|
SECU_PrintError(progName, "unable to allocate cert trust");
|
|
return SECFailure;
|
|
}
|
|
|
|
/* This function only decodes these characters: pPwcTCu, */
|
|
rv = CERT_DecodeTrustString(trust, trusts);
|
|
if (rv) {
|
|
SECU_PrintError(progName, "unable to decode trust string");
|
|
return SECFailure;
|
|
}
|
|
|
|
/* CERT_ChangeCertTrust API does not have a way to pass in
|
|
* a context, so NSS can't prompt for the password if it needs to.
|
|
* check to see if the failure was token not logged in and
|
|
* log in if need be. */
|
|
rv = CERT_ChangeCertTrust(handle, cert, trust);
|
|
if (rv != SECSuccess) {
|
|
if (PORT_GetError() == SEC_ERROR_TOKEN_NOT_LOGGED_IN) {
|
|
rv = PK11_Authenticate(slot, PR_TRUE, pwdata);
|
|
if (rv != SECSuccess) {
|
|
SECU_PrintError(progName, "could not authenticate to token %s.",
|
|
PK11_GetTokenName(slot));
|
|
return SECFailure;
|
|
}
|
|
rv = CERT_ChangeCertTrust(handle, cert, trust);
|
|
}
|
|
if (rv != SECSuccess) {
|
|
SECU_PrintError(progName, "unable to modify trust attributes");
|
|
return SECFailure;
|
|
}
|
|
}
|
|
CERT_DestroyCertificate(cert);
|
|
|
|
return SECSuccess;
|
|
}
|
|
|
|
static SECStatus
|
|
DumpChain(CERTCertDBHandle *handle, char *name, PRBool ascii)
|
|
{
|
|
CERTCertificate *the_cert;
|
|
CERTCertificateList *chain;
|
|
int i, j;
|
|
the_cert = SECU_FindCertByNicknameOrFilename(handle, name,
|
|
ascii, NULL);
|
|
if (!the_cert) {
|
|
SECU_PrintError(progName, "Could not find: %s\n", name);
|
|
return SECFailure;
|
|
}
|
|
chain = CERT_CertChainFromCert(the_cert, 0, PR_TRUE);
|
|
CERT_DestroyCertificate(the_cert);
|
|
if (!chain) {
|
|
SECU_PrintError(progName, "Could not obtain chain for: %s\n", name);
|
|
return SECFailure;
|
|
}
|
|
for (i=chain->len-1; i>=0; i--) {
|
|
CERTCertificate *c;
|
|
c = CERT_FindCertByDERCert(handle, &chain->certs[i]);
|
|
for (j=i; j<chain->len-1; j++) printf(" ");
|
|
printf("\"%s\" [%s]\n\n", c->nickname, c->subjectName);
|
|
CERT_DestroyCertificate(c);
|
|
}
|
|
CERT_DestroyCertificateList(chain);
|
|
return SECSuccess;
|
|
}
|
|
|
|
static SECStatus
|
|
outputCertOrExtension(CERTCertificate *the_cert, PRBool raw, PRBool ascii,
|
|
SECItem *extensionOID, PRFileDesc *outfile)
|
|
{
|
|
SECItem data;
|
|
PRInt32 numBytes;
|
|
SECStatus rv = SECFailure;
|
|
if (extensionOID) {
|
|
int i;
|
|
PRBool found = PR_FALSE;
|
|
for (i=0; the_cert->extensions[i] != NULL; i++) {
|
|
CERTCertExtension *extension = the_cert->extensions[i];
|
|
if (SECITEM_CompareItem(&extension->id, extensionOID) == SECEqual) {
|
|
found = PR_TRUE;
|
|
numBytes = PR_Write(outfile, extension->value.data,
|
|
extension->value.len);
|
|
rv = SECSuccess;
|
|
if (numBytes != (PRInt32) extension->value.len) {
|
|
SECU_PrintSystemError(progName, "error writing extension");
|
|
rv = SECFailure;
|
|
}
|
|
rv = SECSuccess;
|
|
break;
|
|
}
|
|
}
|
|
if (!found) {
|
|
SECU_PrintSystemError(progName, "extension not found");
|
|
rv = SECFailure;
|
|
}
|
|
} else {
|
|
data.data = the_cert->derCert.data;
|
|
data.len = the_cert->derCert.len;
|
|
if (ascii) {
|
|
PR_fprintf(outfile, "%s\n%s\n%s\n", NS_CERT_HEADER,
|
|
BTOA_DataToAscii(data.data, data.len), NS_CERT_TRAILER);
|
|
rv = SECSuccess;
|
|
} else if (raw) {
|
|
numBytes = PR_Write(outfile, data.data, data.len);
|
|
rv = SECSuccess;
|
|
if (numBytes != (PRInt32) data.len) {
|
|
SECU_PrintSystemError(progName, "error writing raw cert");
|
|
rv = SECFailure;
|
|
}
|
|
} else {
|
|
rv = SEC_PrintCertificateAndTrust(the_cert, "Certificate", NULL);
|
|
if (rv != SECSuccess) {
|
|
SECU_PrintError(progName, "problem printing certificate");
|
|
}
|
|
}
|
|
}
|
|
return rv;
|
|
}
|
|
|
|
static SECStatus
|
|
listCerts(CERTCertDBHandle *handle, char *name, char *email,
|
|
PK11SlotInfo *slot, PRBool raw, PRBool ascii,
|
|
SECItem *extensionOID,
|
|
PRFileDesc *outfile, void *pwarg)
|
|
{
|
|
SECStatus rv = SECFailure;
|
|
CERTCertList *certs;
|
|
CERTCertListNode *node;
|
|
|
|
/* List certs on a non-internal slot. */
|
|
if (!PK11_IsFriendly(slot) && PK11_NeedLogin(slot)) {
|
|
SECStatus newrv = PK11_Authenticate(slot, PR_TRUE, pwarg);
|
|
if (newrv != SECSuccess) {
|
|
SECU_PrintError(progName, "could not authenticate to token %s.",
|
|
PK11_GetTokenName(slot));
|
|
return SECFailure;
|
|
}
|
|
}
|
|
if (name) {
|
|
CERTCertificate *the_cert =
|
|
SECU_FindCertByNicknameOrFilename(handle, name, ascii, NULL);
|
|
if (!the_cert) {
|
|
SECU_PrintError(progName, "Could not find cert: %s\n", name);
|
|
return SECFailure;
|
|
}
|
|
/* Here, we have one cert with the desired nickname or email
|
|
* address. Now, we will attempt to get a list of ALL certs
|
|
* with the same subject name as the cert we have. That list
|
|
* should contain, at a minimum, the one cert we have already found.
|
|
* If the list of certs is empty (NULL), the libraries have failed.
|
|
*/
|
|
certs = CERT_CreateSubjectCertList(NULL, handle, &the_cert->derSubject,
|
|
PR_Now(), PR_FALSE);
|
|
CERT_DestroyCertificate(the_cert);
|
|
if (!certs) {
|
|
PORT_SetError(SEC_ERROR_LIBRARY_FAILURE);
|
|
SECU_PrintError(progName, "problem printing certificates");
|
|
return SECFailure;
|
|
}
|
|
for (node = CERT_LIST_HEAD(certs); !CERT_LIST_END(node,certs);
|
|
node = CERT_LIST_NEXT(node)) {
|
|
rv = outputCertOrExtension(node->cert, raw, ascii, extensionOID,
|
|
outfile);
|
|
if (rv != SECSuccess) {
|
|
break;
|
|
}
|
|
}
|
|
} else if (email) {
|
|
certs = PK11_FindCertsFromEmailAddress(email, NULL);
|
|
if (!certs) {
|
|
SECU_PrintError(progName,
|
|
"Could not find certificates for email address: %s\n",
|
|
email);
|
|
return SECFailure;
|
|
}
|
|
for (node = CERT_LIST_HEAD(certs); !CERT_LIST_END(node,certs);
|
|
node = CERT_LIST_NEXT(node)) {
|
|
rv = outputCertOrExtension(node->cert, raw, ascii, extensionOID,
|
|
outfile);
|
|
if (rv != SECSuccess) {
|
|
break;
|
|
}
|
|
}
|
|
} else {
|
|
certs = PK11_ListCertsInSlot(slot);
|
|
if (certs) {
|
|
for (node = CERT_LIST_HEAD(certs); !CERT_LIST_END(node,certs);
|
|
node = CERT_LIST_NEXT(node)) {
|
|
SECU_PrintCertNickname(node,stdout);
|
|
}
|
|
rv = SECSuccess;
|
|
}
|
|
}
|
|
if (certs) {
|
|
CERT_DestroyCertList(certs);
|
|
}
|
|
if (rv) {
|
|
SECU_PrintError(progName, "problem printing certificate nicknames");
|
|
return SECFailure;
|
|
}
|
|
|
|
return SECSuccess; /* not rv ?? */
|
|
}
|
|
|
|
static SECStatus
|
|
ListCerts(CERTCertDBHandle *handle, char *nickname, char *email,
|
|
PK11SlotInfo *slot, PRBool raw, PRBool ascii,
|
|
SECItem *extensionOID,
|
|
PRFileDesc *outfile, secuPWData *pwdata)
|
|
{
|
|
SECStatus rv;
|
|
|
|
if (!ascii && !raw && !nickname && !email) {
|
|
PR_fprintf(outfile, "\n%-60s %-5s\n%-60s %-5s\n\n",
|
|
"Certificate Nickname", "Trust Attributes", "",
|
|
"SSL,S/MIME,JAR/XPI");
|
|
}
|
|
if (slot == NULL) {
|
|
CERTCertList *list;
|
|
CERTCertListNode *node;
|
|
|
|
list = PK11_ListCerts(PK11CertListAll, pwdata);
|
|
for (node = CERT_LIST_HEAD(list); !CERT_LIST_END(node, list);
|
|
node = CERT_LIST_NEXT(node)) {
|
|
SECU_PrintCertNickname(node, stdout);
|
|
}
|
|
CERT_DestroyCertList(list);
|
|
return SECSuccess;
|
|
}
|
|
rv = listCerts(handle, nickname, email, slot, raw, ascii,
|
|
extensionOID, outfile, pwdata);
|
|
return rv;
|
|
}
|
|
|
|
static SECStatus
|
|
DeleteCert(CERTCertDBHandle *handle, char *name)
|
|
{
|
|
SECStatus rv;
|
|
CERTCertificate *cert;
|
|
|
|
cert = CERT_FindCertByNicknameOrEmailAddr(handle, name);
|
|
if (!cert) {
|
|
SECU_PrintError(progName, "could not find certificate named \"%s\"",
|
|
name);
|
|
return SECFailure;
|
|
}
|
|
|
|
rv = SEC_DeletePermCertificate(cert);
|
|
CERT_DestroyCertificate(cert);
|
|
if (rv) {
|
|
SECU_PrintError(progName, "unable to delete certificate");
|
|
}
|
|
return rv;
|
|
}
|
|
|
|
static SECStatus
|
|
ValidateCert(CERTCertDBHandle *handle, char *name, char *date,
|
|
char *certUsage, PRBool checkSig, PRBool logit,
|
|
PRBool ascii, secuPWData *pwdata)
|
|
{
|
|
SECStatus rv;
|
|
CERTCertificate *cert = NULL;
|
|
PRTime timeBoundary;
|
|
SECCertificateUsage usage;
|
|
CERTVerifyLog reallog;
|
|
CERTVerifyLog *log = NULL;
|
|
|
|
if (!certUsage) {
|
|
PORT_SetError (SEC_ERROR_INVALID_ARGS);
|
|
return (SECFailure);
|
|
}
|
|
|
|
switch (*certUsage) {
|
|
case 'O':
|
|
usage = certificateUsageStatusResponder;
|
|
break;
|
|
case 'L':
|
|
usage = certificateUsageSSLCA;
|
|
break;
|
|
case 'A':
|
|
usage = certificateUsageAnyCA;
|
|
break;
|
|
case 'Y':
|
|
usage = certificateUsageVerifyCA;
|
|
break;
|
|
case 'C':
|
|
usage = certificateUsageSSLClient;
|
|
break;
|
|
case 'V':
|
|
usage = certificateUsageSSLServer;
|
|
break;
|
|
case 'S':
|
|
usage = certificateUsageEmailSigner;
|
|
break;
|
|
case 'R':
|
|
usage = certificateUsageEmailRecipient;
|
|
break;
|
|
case 'J':
|
|
usage = certificateUsageObjectSigner;
|
|
break;
|
|
default:
|
|
PORT_SetError (SEC_ERROR_INVALID_ARGS);
|
|
return (SECFailure);
|
|
}
|
|
do {
|
|
cert = SECU_FindCertByNicknameOrFilename(handle, name, ascii,
|
|
NULL);
|
|
if (!cert) {
|
|
SECU_PrintError(progName, "could not find certificate named \"%s\"",
|
|
name);
|
|
GEN_BREAK (SECFailure)
|
|
}
|
|
|
|
if (date != NULL) {
|
|
rv = DER_AsciiToTime(&timeBoundary, date);
|
|
if (rv) {
|
|
SECU_PrintError(progName, "invalid input date");
|
|
GEN_BREAK (SECFailure)
|
|
}
|
|
} else {
|
|
timeBoundary = PR_Now();
|
|
}
|
|
|
|
if ( logit ) {
|
|
log = &reallog;
|
|
|
|
log->count = 0;
|
|
log->head = NULL;
|
|
log->tail = NULL;
|
|
log->arena = PORT_NewArena(DER_DEFAULT_CHUNKSIZE);
|
|
if ( log->arena == NULL ) {
|
|
SECU_PrintError(progName, "out of memory");
|
|
GEN_BREAK (SECFailure)
|
|
}
|
|
}
|
|
|
|
rv = CERT_VerifyCertificate(handle, cert, checkSig, usage,
|
|
timeBoundary, pwdata, log, &usage);
|
|
if ( log ) {
|
|
if ( log->head == NULL ) {
|
|
fprintf(stdout, "%s: certificate is valid\n", progName);
|
|
GEN_BREAK (SECSuccess)
|
|
} else {
|
|
char *name;
|
|
CERTVerifyLogNode *node;
|
|
|
|
node = log->head;
|
|
while ( node ) {
|
|
if ( node->cert->nickname != NULL ) {
|
|
name = node->cert->nickname;
|
|
} else {
|
|
name = node->cert->subjectName;
|
|
}
|
|
fprintf(stderr, "%s : %s\n", name,
|
|
SECU_Strerror(node->error));
|
|
CERT_DestroyCertificate(node->cert);
|
|
node = node->next;
|
|
}
|
|
}
|
|
} else {
|
|
if (rv != SECSuccess) {
|
|
PRErrorCode perr = PORT_GetError();
|
|
fprintf(stdout, "%s: certificate is invalid: %s\n",
|
|
progName, SECU_Strerror(perr));
|
|
GEN_BREAK (SECFailure)
|
|
}
|
|
fprintf(stdout, "%s: certificate is valid\n", progName);
|
|
GEN_BREAK (SECSuccess)
|
|
}
|
|
} while (0);
|
|
|
|
if (cert) {
|
|
CERT_DestroyCertificate(cert);
|
|
}
|
|
|
|
return (rv);
|
|
}
|
|
|
|
static PRBool
|
|
ItemIsPrintableASCII(const SECItem * item)
|
|
{
|
|
unsigned char *src = item->data;
|
|
unsigned int len = item->len;
|
|
while (len-- > 0) {
|
|
unsigned char uc = *src++;
|
|
if (uc < 0x20 || uc > 0x7e)
|
|
return PR_FALSE;
|
|
}
|
|
return PR_TRUE;
|
|
}
|
|
|
|
/* Caller ensures that dst is at least item->len*2+1 bytes long */
|
|
static void
|
|
SECItemToHex(const SECItem * item, char * dst)
|
|
{
|
|
if (dst && item && item->data) {
|
|
unsigned char * src = item->data;
|
|
unsigned int len = item->len;
|
|
for (; len > 0; --len, dst += 2) {
|
|
sprintf(dst, "%02x", *src++);
|
|
}
|
|
*dst = '\0';
|
|
}
|
|
}
|
|
|
|
static const char * const keyTypeName[] = {
|
|
"null", "rsa", "dsa", "fortezza", "dh", "kea", "ec" };
|
|
|
|
#define MAX_CKA_ID_BIN_LEN 20
|
|
#define MAX_CKA_ID_STR_LEN 40
|
|
|
|
/* print key number, key ID (in hex or ASCII), key label (nickname) */
|
|
static SECStatus
|
|
PrintKey(PRFileDesc *out, const char *nickName, int count,
|
|
SECKEYPrivateKey *key, void *pwarg)
|
|
{
|
|
SECItem * ckaID;
|
|
char ckaIDbuf[MAX_CKA_ID_STR_LEN + 4];
|
|
|
|
pwarg = NULL;
|
|
ckaID = PK11_GetLowLevelKeyIDForPrivateKey(key);
|
|
if (!ckaID) {
|
|
strcpy(ckaIDbuf, "(no CKA_ID)");
|
|
} else if (ItemIsPrintableASCII(ckaID)) {
|
|
int len = PR_MIN(MAX_CKA_ID_STR_LEN, ckaID->len);
|
|
ckaIDbuf[0] = '"';
|
|
memcpy(ckaIDbuf + 1, ckaID->data, len);
|
|
ckaIDbuf[1 + len] = '"';
|
|
ckaIDbuf[2 + len] = '\0';
|
|
} else {
|
|
/* print ckaid in hex */
|
|
SECItem idItem = *ckaID;
|
|
if (idItem.len > MAX_CKA_ID_BIN_LEN)
|
|
idItem.len = MAX_CKA_ID_BIN_LEN;
|
|
SECItemToHex(&idItem, ckaIDbuf);
|
|
}
|
|
|
|
PR_fprintf(out, "<%2d> %-8.8s %-42.42s %s\n", count,
|
|
keyTypeName[key->keyType], ckaIDbuf, nickName);
|
|
SECITEM_ZfreeItem(ckaID, PR_TRUE);
|
|
|
|
return SECSuccess;
|
|
}
|
|
|
|
/* returns SECSuccess if ANY keys are found, SECFailure otherwise. */
|
|
static SECStatus
|
|
ListKeysInSlot(PK11SlotInfo *slot, const char *nickName, KeyType keyType,
|
|
void *pwarg)
|
|
{
|
|
SECKEYPrivateKeyList *list;
|
|
SECKEYPrivateKeyListNode *node;
|
|
int count = 0;
|
|
|
|
if (PK11_NeedLogin(slot)) {
|
|
SECStatus rv = PK11_Authenticate(slot, PR_TRUE, pwarg);
|
|
if (rv != SECSuccess) {
|
|
SECU_PrintError(progName, "could not authenticate to token %s.",
|
|
PK11_GetTokenName(slot));
|
|
return SECFailure;
|
|
}
|
|
}
|
|
|
|
if (nickName && nickName[0])
|
|
list = PK11_ListPrivKeysInSlot(slot, (char *)nickName, pwarg);
|
|
else
|
|
list = PK11_ListPrivateKeysInSlot(slot);
|
|
if (list == NULL) {
|
|
SECU_PrintError(progName, "problem listing keys");
|
|
return SECFailure;
|
|
}
|
|
for (node=PRIVKEY_LIST_HEAD(list);
|
|
!PRIVKEY_LIST_END(node,list);
|
|
node=PRIVKEY_LIST_NEXT(node)) {
|
|
char * keyName;
|
|
static const char orphan[] = { "(orphan)" };
|
|
|
|
if (keyType != nullKey && keyType != node->key->keyType)
|
|
continue;
|
|
keyName = PK11_GetPrivateKeyNickname(node->key);
|
|
if (!keyName || !keyName[0]) {
|
|
/* Try extra hard to find nicknames for keys that lack them. */
|
|
CERTCertificate * cert;
|
|
PORT_Free((void *)keyName);
|
|
keyName = NULL;
|
|
cert = PK11_GetCertFromPrivateKey(node->key);
|
|
if (cert) {
|
|
if (cert->nickname && cert->nickname[0]) {
|
|
keyName = PORT_Strdup(cert->nickname);
|
|
} else if (cert->emailAddr && cert->emailAddr[0]) {
|
|
keyName = PORT_Strdup(cert->emailAddr);
|
|
}
|
|
CERT_DestroyCertificate(cert);
|
|
}
|
|
}
|
|
if (nickName) {
|
|
if (!keyName || PL_strcmp(keyName,nickName)) {
|
|
/* PKCS#11 module returned unwanted keys */
|
|
PORT_Free((void *)keyName);
|
|
continue;
|
|
}
|
|
}
|
|
if (!keyName)
|
|
keyName = (char *)orphan;
|
|
|
|
PrintKey(PR_STDOUT, keyName, count, node->key, pwarg);
|
|
|
|
if (keyName != (char *)orphan)
|
|
PORT_Free((void *)keyName);
|
|
count++;
|
|
}
|
|
SECKEY_DestroyPrivateKeyList(list);
|
|
|
|
if (count == 0) {
|
|
PR_fprintf(PR_STDOUT, "%s: no keys found\n", progName);
|
|
return SECFailure;
|
|
}
|
|
return SECSuccess;
|
|
}
|
|
|
|
/* returns SECSuccess if ANY keys are found, SECFailure otherwise. */
|
|
static SECStatus
|
|
ListKeys(PK11SlotInfo *slot, const char *nickName, int index,
|
|
KeyType keyType, PRBool dopriv, secuPWData *pwdata)
|
|
{
|
|
SECStatus rv = SECFailure;
|
|
static const char fmt[] = \
|
|
"%s: Checking token \"%.33s\" in slot \"%.65s\"\n";
|
|
|
|
if (slot == NULL) {
|
|
PK11SlotList *list;
|
|
PK11SlotListElement *le;
|
|
|
|
list= PK11_GetAllTokens(CKM_INVALID_MECHANISM,PR_FALSE,PR_FALSE,pwdata);
|
|
if (list) {
|
|
for (le = list->head; le; le = le->next) {
|
|
PR_fprintf(PR_STDOUT, fmt, progName,
|
|
PK11_GetTokenName(le->slot),
|
|
PK11_GetSlotName(le->slot));
|
|
rv &= ListKeysInSlot(le->slot,nickName,keyType,pwdata);
|
|
}
|
|
PK11_FreeSlotList(list);
|
|
}
|
|
} else {
|
|
PR_fprintf(PR_STDOUT, fmt, progName, PK11_GetTokenName(slot),
|
|
PK11_GetSlotName(slot));
|
|
rv = ListKeysInSlot(slot,nickName,keyType,pwdata);
|
|
}
|
|
return rv;
|
|
}
|
|
|
|
static SECStatus
|
|
DeleteKey(char *nickname, secuPWData *pwdata)
|
|
{
|
|
SECStatus rv;
|
|
CERTCertificate *cert;
|
|
PK11SlotInfo *slot;
|
|
|
|
slot = PK11_GetInternalKeySlot();
|
|
if (PK11_NeedLogin(slot)) {
|
|
SECStatus rv = PK11_Authenticate(slot, PR_TRUE, pwdata);
|
|
if (rv != SECSuccess) {
|
|
SECU_PrintError(progName, "could not authenticate to token %s.",
|
|
PK11_GetTokenName(slot));
|
|
return SECFailure;
|
|
}
|
|
}
|
|
cert = PK11_FindCertFromNickname(nickname, pwdata);
|
|
if (!cert) {
|
|
PK11_FreeSlot(slot);
|
|
return SECFailure;
|
|
}
|
|
rv = PK11_DeleteTokenCertAndKey(cert, pwdata);
|
|
if (rv != SECSuccess) {
|
|
SECU_PrintError("problem deleting private key \"%s\"\n", nickname);
|
|
}
|
|
CERT_DestroyCertificate(cert);
|
|
PK11_FreeSlot(slot);
|
|
return rv;
|
|
}
|
|
|
|
|
|
/*
|
|
* L i s t M o d u l e s
|
|
*
|
|
* Print a list of the PKCS11 modules that are
|
|
* available. This is useful for smartcard people to
|
|
* make sure they have the drivers loaded.
|
|
*
|
|
*/
|
|
static SECStatus
|
|
ListModules(void)
|
|
{
|
|
PK11SlotList *list;
|
|
PK11SlotListElement *le;
|
|
|
|
/* get them all! */
|
|
list = PK11_GetAllTokens(CKM_INVALID_MECHANISM,PR_FALSE,PR_FALSE,NULL);
|
|
if (list == NULL) return SECFailure;
|
|
|
|
/* look at each slot*/
|
|
for (le = list->head ; le; le = le->next) {
|
|
printf ("\n");
|
|
printf (" slot: %s\n", PK11_GetSlotName(le->slot));
|
|
printf (" token: %s\n", PK11_GetTokenName(le->slot));
|
|
}
|
|
PK11_FreeSlotList(list);
|
|
|
|
return SECSuccess;
|
|
}
|
|
|
|
static void
|
|
PrintSyntax(char *progName)
|
|
{
|
|
#define FPS fprintf(stderr,
|
|
FPS "Type %s -H for more detailed descriptions\n", progName);
|
|
FPS "Usage: %s -N [-d certdir] [-P dbprefix] [-f pwfile] [--empty-password]\n", progName);
|
|
FPS "Usage: %s -T [-d certdir] [-P dbprefix] [-h token-name]\n"
|
|
"\t\t [-f pwfile] [-0 SSO-password]\n", progName);
|
|
FPS "\t%s -A -n cert-name -t trustargs [-d certdir] [-P dbprefix] [-a] [-i input]\n",
|
|
progName);
|
|
FPS "\t%s -B -i batch-file\n", progName);
|
|
FPS "\t%s -C [-c issuer-name | -x] -i cert-request-file -o cert-file\n"
|
|
"\t\t [-m serial-number] [-w warp-months] [-v months-valid]\n"
|
|
"\t\t [-f pwfile] [-d certdir] [-P dbprefix] [-Z hashAlg]\n"
|
|
"\t\t [-1 | --keyUsage [keyUsageKeyword,..]] [-2] [-3] [-4]\n"
|
|
"\t\t [-5 | --nsCertType [nsCertTypeKeyword,...]]\n"
|
|
"\t\t [-6 | --extKeyUsage [extKeyUsageKeyword,...]] [-7 emailAddrs]\n"
|
|
"\t\t [-8 dns-names] [-a]\n",
|
|
progName);
|
|
FPS "\t%s -D -n cert-name [-d certdir] [-P dbprefix]\n", progName);
|
|
FPS "\t%s -E -n cert-name -t trustargs [-d certdir] [-P dbprefix] [-a] [-i input]\n",
|
|
progName);
|
|
FPS "\t%s -F -n nickname [-d certdir] [-P dbprefix]\n",
|
|
progName);
|
|
FPS "\t%s -G -n key-name [-h token-name] [-k rsa] [-g key-size] [-y exp]\n"
|
|
"\t\t [-f pwfile] [-z noisefile] [-d certdir] [-P dbprefix]\n", progName);
|
|
FPS "\t%s -G [-h token-name] -k dsa [-q pqgfile -g key-size] [-f pwfile]\n"
|
|
"\t\t [-z noisefile] [-d certdir] [-P dbprefix]\n", progName);
|
|
#ifndef NSS_DISABLE_ECC
|
|
FPS "\t%s -G [-h token-name] -k ec -q curve [-f pwfile]\n"
|
|
"\t\t [-z noisefile] [-d certdir] [-P dbprefix]\n", progName);
|
|
FPS "\t%s -K [-n key-name] [-h token-name] [-k dsa|ec|rsa|all]\n",
|
|
progName);
|
|
#else
|
|
FPS "\t%s -K [-n key-name] [-h token-name] [-k dsa|rsa|all]\n",
|
|
progName);
|
|
#endif /* NSS_DISABLE_ECC */
|
|
FPS "\t\t [-f pwfile] [-X] [-d certdir] [-P dbprefix]\n");
|
|
FPS "\t%s --upgrade-merge --source-dir upgradeDir --upgrade-id uniqueID\n",
|
|
progName);
|
|
FPS "\t\t [--upgrade-token-name tokenName] [-d targetDBDir]\n");
|
|
FPS "\t\t [-P targetDBPrefix] [--source-prefix upgradeDBPrefix]\n");
|
|
FPS "\t\t [-f targetPWfile] [-@ upgradePWFile]\n");
|
|
FPS "\t%s --merge --source-dir sourceDBDir [-d targetDBdir]\n",
|
|
progName);
|
|
FPS "\t\t [-P targetDBPrefix] [--source-prefix sourceDBPrefix]\n");
|
|
FPS "\t\t [-f targetPWfile] [-@ sourcePWFile]\n");
|
|
FPS "\t%s -L [-n cert-name] [-h token-name] [--email email-address]\n",
|
|
progName);
|
|
FPS "\t\t [-X] [-r] [-a] [--dump-ext-val OID] [-d certdir] [-P dbprefix]\n");
|
|
FPS "\t%s -M -n cert-name -t trustargs [-d certdir] [-P dbprefix]\n",
|
|
progName);
|
|
FPS "\t%s -O -n cert-name [-X] [-d certdir] [-a] [-P dbprefix]\n", progName);
|
|
FPS "\t%s -R -s subj -o cert-request-file [-d certdir] [-P dbprefix] [-p phone] [-a]\n"
|
|
"\t\t [-7 emailAddrs] [-k key-type-or-id] [-h token-name] [-f pwfile]\n"
|
|
"\t\t [-g key-size] [-Z hashAlg]\n",
|
|
progName);
|
|
FPS "\t%s -V -n cert-name -u usage [-b time] [-e] [-a]\n"
|
|
"\t\t[-X] [-d certdir] [-P dbprefix]\n",
|
|
progName);
|
|
FPS "Usage: %s -W [-d certdir] [-f pwfile] [-@newpwfile]\n",
|
|
progName);
|
|
FPS "\t%s -S -n cert-name -s subj [-c issuer-name | -x] -t trustargs\n"
|
|
"\t\t [-k key-type-or-id] [-q key-params] [-h token-name] [-g key-size]\n"
|
|
"\t\t [-m serial-number] [-w warp-months] [-v months-valid]\n"
|
|
"\t\t [-f pwfile] [-d certdir] [-P dbprefix] [-Z hashAlg]\n"
|
|
"\t\t [-p phone] [-1] [-2] [-3] [-4] [-5] [-6] [-7 emailAddrs]\n"
|
|
"\t\t [-8 DNS-names]\n"
|
|
"\t\t [--extAIA] [--extSIA] [--extCP] [--extPM] [--extPC] [--extIA]\n"
|
|
"\t\t [--extSKID] [--extNC] [--extSAN type:name[,type:name]...]\n"
|
|
"\t\t [--extGeneric OID:critical-flag:filename[,OID:critical-flag:filename]...]\n", progName);
|
|
FPS "\t%s -U [-X] [-d certdir] [-P dbprefix]\n", progName);
|
|
exit(1);
|
|
}
|
|
|
|
enum usage_level {
|
|
usage_all = 0, usage_selected = 1
|
|
};
|
|
|
|
static void luCommonDetailsAE();
|
|
|
|
static void luA(enum usage_level ul, const char *command)
|
|
{
|
|
int is_my_command = (command && 0 == strcmp(command, "A"));
|
|
if (ul == usage_all || !command || is_my_command)
|
|
FPS "%-15s Add a certificate to the database (create if needed)\n",
|
|
"-A");
|
|
if (ul == usage_selected && !is_my_command)
|
|
return;
|
|
if (ul == usage_all) {
|
|
FPS "%-20s\n", " All options under -E apply");
|
|
}
|
|
else {
|
|
luCommonDetailsAE();
|
|
}
|
|
}
|
|
|
|
static void luB(enum usage_level ul, const char *command)
|
|
{
|
|
int is_my_command = (command && 0 == strcmp(command, "B"));
|
|
if (ul == usage_all || !command || is_my_command)
|
|
FPS "%-15s Run a series of certutil commands from a batch file\n", "-B");
|
|
if (ul == usage_selected && !is_my_command)
|
|
return;
|
|
FPS "%-20s Specify the batch file\n", " -i batch-file");
|
|
}
|
|
|
|
static void luE(enum usage_level ul, const char *command)
|
|
{
|
|
int is_my_command = (command && 0 == strcmp(command, "E"));
|
|
if (ul == usage_all || !command || is_my_command)
|
|
FPS "%-15s Add an Email certificate to the database (create if needed)\n",
|
|
"-E");
|
|
if (ul == usage_selected && !is_my_command)
|
|
return;
|
|
luCommonDetailsAE();
|
|
}
|
|
|
|
static void luCommonDetailsAE()
|
|
{
|
|
FPS "%-20s Specify the nickname of the certificate to add\n",
|
|
" -n cert-name");
|
|
FPS "%-20s Set the certificate trust attributes:\n",
|
|
" -t trustargs");
|
|
FPS "%-25s trustargs is of the form x,y,z where x is for SSL, y is for S/MIME,\n", "");
|
|
FPS "%-25s and z is for code signing. Use ,, for no explicit trust.\n", "");
|
|
FPS "%-25s p \t prohibited (explicitly distrusted)\n", "");
|
|
FPS "%-25s P \t trusted peer\n", "");
|
|
FPS "%-25s c \t valid CA\n", "");
|
|
FPS "%-25s T \t trusted CA to issue client certs (implies c)\n", "");
|
|
FPS "%-25s C \t trusted CA to issue server certs (implies c)\n", "");
|
|
FPS "%-25s u \t user cert\n", "");
|
|
FPS "%-25s w \t send warning\n", "");
|
|
FPS "%-25s g \t make step-up cert\n", "");
|
|
FPS "%-20s Specify the password file\n",
|
|
" -f pwfile");
|
|
FPS "%-20s Cert database directory (default is ~/.netscape)\n",
|
|
" -d certdir");
|
|
FPS "%-20s Cert & Key database prefix\n",
|
|
" -P dbprefix");
|
|
FPS "%-20s The input certificate is encoded in ASCII (RFC1113)\n",
|
|
" -a");
|
|
FPS "%-20s Specify the certificate file (default is stdin)\n",
|
|
" -i input");
|
|
FPS "\n");
|
|
}
|
|
|
|
static void luC(enum usage_level ul, const char *command)
|
|
{
|
|
int is_my_command = (command && 0 == strcmp(command, "C"));
|
|
if (ul == usage_all || !command || is_my_command)
|
|
FPS "%-15s Create a new binary certificate from a BINARY cert request\n",
|
|
"-C");
|
|
if (ul == usage_selected && !is_my_command)
|
|
return;
|
|
FPS "%-20s The nickname of the issuer cert\n",
|
|
" -c issuer-name");
|
|
FPS "%-20s The BINARY certificate request file\n",
|
|
" -i cert-request ");
|
|
FPS "%-20s Output binary cert to this file (default is stdout)\n",
|
|
" -o output-cert");
|
|
FPS "%-20s Self sign\n",
|
|
" -x");
|
|
FPS "%-20s Cert serial number\n",
|
|
" -m serial-number");
|
|
FPS "%-20s Time Warp\n",
|
|
" -w warp-months");
|
|
FPS "%-20s Months valid (default is 3)\n",
|
|
" -v months-valid");
|
|
FPS "%-20s Specify the password file\n",
|
|
" -f pwfile");
|
|
FPS "%-20s Cert database directory (default is ~/.netscape)\n",
|
|
" -d certdir");
|
|
FPS "%-20s Cert & Key database prefix\n",
|
|
" -P dbprefix");
|
|
FPS "%-20s \n"
|
|
"%-20s Specify the hash algorithm to use. Possible keywords:\n"
|
|
"%-20s \"MD2\", \"MD4\", \"MD5\", \"SHA1\", \"SHA224\",\n"
|
|
"%-20s \"SHA256\", \"SHA384\", \"SHA512\"\n",
|
|
" -Z hashAlg", "", "", "");
|
|
FPS "%-20s \n"
|
|
"%-20s Create key usage extension. Possible keywords:\n"
|
|
"%-20s \"digitalSignature\", \"nonRepudiation\", \"keyEncipherment\",\n"
|
|
"%-20s \"dataEncipherment\", \"keyAgreement\", \"certSigning\",\n"
|
|
"%-20s \"crlSigning\", \"critical\"\n",
|
|
" -1 | --keyUsage keyword,keyword,...", "", "", "", "");
|
|
FPS "%-20s Create basic constraint extension\n",
|
|
" -2 ");
|
|
FPS "%-20s Create authority key ID extension\n",
|
|
" -3 ");
|
|
FPS "%-20s Create crl distribution point extension\n",
|
|
" -4 ");
|
|
FPS "%-20s \n"
|
|
"%-20s Create netscape cert type extension. Possible keywords:\n"
|
|
"%-20s \"sslClient\", \"sslServer\", \"smime\", \"objectSigning\",\n"
|
|
"%-20s \"sslCA\", \"smimeCA\", \"objectSigningCA\", \"critical\".\n",
|
|
" -5 | --nsCertType keyword,keyword,... ", "", "", "");
|
|
FPS "%-20s \n"
|
|
"%-20s Create extended key usage extension. Possible keywords:\n"
|
|
"%-20s \"serverAuth\", \"clientAuth\",\"codeSigning\",\n"
|
|
"%-20s \"emailProtection\", \"timeStamp\",\"ocspResponder\",\n"
|
|
"%-20s \"stepUp\", \"msTrustListSign\", \"critical\"\n",
|
|
" -6 | --extKeyUsage keyword,keyword,...", "", "", "", "");
|
|
FPS "%-20s Create an email subject alt name extension\n",
|
|
" -7 emailAddrs");
|
|
FPS "%-20s Create an dns subject alt name extension\n",
|
|
" -8 dnsNames");
|
|
FPS "%-20s The input certificate request is encoded in ASCII (RFC1113)\n",
|
|
" -a");
|
|
FPS "\n");
|
|
}
|
|
|
|
static void luG(enum usage_level ul, const char *command)
|
|
{
|
|
int is_my_command = (command && 0 == strcmp(command, "G"));
|
|
if (ul == usage_all || !command || is_my_command)
|
|
FPS "%-15s Generate a new key pair\n",
|
|
"-G");
|
|
if (ul == usage_selected && !is_my_command)
|
|
return;
|
|
FPS "%-20s Name of token in which to generate key (default is internal)\n",
|
|
" -h token-name");
|
|
#ifndef NSS_DISABLE_ECC
|
|
FPS "%-20s Type of key pair to generate (\"dsa\", \"ec\", \"rsa\" (default))\n",
|
|
" -k key-type");
|
|
FPS "%-20s Key size in bits, (min %d, max %d, default %d) (not for ec)\n",
|
|
" -g key-size", MIN_KEY_BITS, MAX_KEY_BITS, DEFAULT_KEY_BITS);
|
|
#else
|
|
FPS "%-20s Type of key pair to generate (\"dsa\", \"rsa\" (default))\n",
|
|
" -k key-type");
|
|
FPS "%-20s Key size in bits, (min %d, max %d, default %d)\n",
|
|
" -g key-size", MIN_KEY_BITS, MAX_KEY_BITS, DEFAULT_KEY_BITS);
|
|
#endif /* NSS_DISABLE_ECC */
|
|
FPS "%-20s Set the public exponent value (3, 17, 65537) (rsa only)\n",
|
|
" -y exp");
|
|
FPS "%-20s Specify the password file\n",
|
|
" -f password-file");
|
|
FPS "%-20s Specify the noise file to be used\n",
|
|
" -z noisefile");
|
|
FPS "%-20s read PQG value from pqgfile (dsa only)\n",
|
|
" -q pqgfile");
|
|
#ifndef NSS_DISABLE_ECC
|
|
FPS "%-20s Elliptic curve name (ec only)\n",
|
|
" -q curve-name");
|
|
FPS "%-20s One of nistp256, nistp384, nistp521\n", "");
|
|
#ifdef NSS_ECC_MORE_THAN_SUITE_B
|
|
FPS "%-20s sect163k1, nistk163, sect163r1, sect163r2,\n", "");
|
|
FPS "%-20s nistb163, sect193r1, sect193r2, sect233k1, nistk233,\n", "");
|
|
FPS "%-20s sect233r1, nistb233, sect239k1, sect283k1, nistk283,\n", "");
|
|
FPS "%-20s sect283r1, nistb283, sect409k1, nistk409, sect409r1,\n", "");
|
|
FPS "%-20s nistb409, sect571k1, nistk571, sect571r1, nistb571,\n", "");
|
|
FPS "%-20s secp160k1, secp160r1, secp160r2, secp192k1, secp192r1,\n", "");
|
|
FPS "%-20s nistp192, secp224k1, secp224r1, nistp224, secp256k1,\n", "");
|
|
FPS "%-20s secp256r1, secp384r1, secp521r1,\n", "");
|
|
FPS "%-20s prime192v1, prime192v2, prime192v3, \n", "");
|
|
FPS "%-20s prime239v1, prime239v2, prime239v3, c2pnb163v1, \n", "");
|
|
FPS "%-20s c2pnb163v2, c2pnb163v3, c2pnb176v1, c2tnb191v1, \n", "");
|
|
FPS "%-20s c2tnb191v2, c2tnb191v3, \n", "");
|
|
FPS "%-20s c2pnb208w1, c2tnb239v1, c2tnb239v2, c2tnb239v3, \n", "");
|
|
FPS "%-20s c2pnb272w1, c2pnb304w1, \n", "");
|
|
FPS "%-20s c2tnb359w1, c2pnb368w1, c2tnb431r1, secp112r1, \n", "");
|
|
FPS "%-20s secp112r2, secp128r1, secp128r2, sect113r1, sect113r2\n", "");
|
|
FPS "%-20s sect131r1, sect131r2\n", "");
|
|
#endif /* NSS_ECC_MORE_THAN_SUITE_B */
|
|
#endif
|
|
FPS "%-20s Key database directory (default is ~/.netscape)\n",
|
|
" -d keydir");
|
|
FPS "%-20s Cert & Key database prefix\n",
|
|
" -P dbprefix");
|
|
FPS "%-20s\n"
|
|
"%-20s PKCS #11 key Attributes.\n",
|
|
" --keyAttrFlags attrflags", "");
|
|
FPS "%-20s Comma separated list of key attribute attribute flags,\n", "");
|
|
FPS "%-20s selected from the following list of choices:\n", "");
|
|
FPS "%-20s {token | session} {public | private} {sensitive | insensitive}\n", "");
|
|
FPS "%-20s {modifiable | unmodifiable} {extractable | unextractable}\n", "");
|
|
FPS "%-20s\n",
|
|
" --keyOpFlagsOn opflags");
|
|
FPS "%-20s\n"
|
|
"%-20s PKCS #11 key Operation Flags.\n",
|
|
" --keyOpFlagsOff opflags", "");
|
|
FPS "%-20s Comma separated list of one or more of the following:\n", "");
|
|
FPS "%-20s encrypt, decrypt, sign, sign_recover, verify,\n", "");
|
|
FPS "%-20s verify_recover, wrap, unwrap, derive\n", "");
|
|
FPS "\n");
|
|
}
|
|
|
|
static void luD(enum usage_level ul, const char *command)
|
|
{
|
|
int is_my_command = (command && 0 == strcmp(command, "D"));
|
|
if (ul == usage_all || !command || is_my_command)
|
|
FPS "%-15s Delete a certificate from the database\n",
|
|
"-D");
|
|
if (ul == usage_selected && !is_my_command)
|
|
return;
|
|
FPS "%-20s The nickname of the cert to delete\n",
|
|
" -n cert-name");
|
|
FPS "%-20s Cert database directory (default is ~/.netscape)\n",
|
|
" -d certdir");
|
|
FPS "%-20s Cert & Key database prefix\n",
|
|
" -P dbprefix");
|
|
FPS "\n");
|
|
|
|
}
|
|
|
|
static void luF(enum usage_level ul, const char *command)
|
|
{
|
|
int is_my_command = (command && 0 == strcmp(command, "F"));
|
|
if (ul == usage_all || !command || is_my_command)
|
|
FPS "%-15s Delete a key from the database\n",
|
|
"-F");
|
|
if (ul == usage_selected && !is_my_command)
|
|
return;
|
|
FPS "%-20s The nickname of the key to delete\n",
|
|
" -n cert-name");
|
|
FPS "%-20s Cert database directory (default is ~/.netscape)\n",
|
|
" -d certdir");
|
|
FPS "%-20s Cert & Key database prefix\n",
|
|
" -P dbprefix");
|
|
FPS "\n");
|
|
|
|
}
|
|
|
|
static void luU(enum usage_level ul, const char *command)
|
|
{
|
|
int is_my_command = (command && 0 == strcmp(command, "U"));
|
|
if (ul == usage_all || !command || is_my_command)
|
|
FPS "%-15s List all modules\n", /*, or print out a single named module\n",*/
|
|
"-U");
|
|
if (ul == usage_selected && !is_my_command)
|
|
return;
|
|
FPS "%-20s Module database directory (default is '~/.netscape')\n",
|
|
" -d moddir");
|
|
FPS "%-20s Cert & Key database prefix\n",
|
|
" -P dbprefix");
|
|
FPS "%-20s force the database to open R/W\n",
|
|
" -X");
|
|
FPS "\n");
|
|
|
|
}
|
|
|
|
static void luK(enum usage_level ul, const char *command)
|
|
{
|
|
int is_my_command = (command && 0 == strcmp(command, "K"));
|
|
if (ul == usage_all || !command || is_my_command)
|
|
FPS "%-15s List all private keys\n",
|
|
"-K");
|
|
if (ul == usage_selected && !is_my_command)
|
|
return;
|
|
FPS "%-20s Name of token to search (\"all\" for all tokens)\n",
|
|
" -h token-name ");
|
|
|
|
FPS "%-20s Key type (\"all\" (default), \"dsa\","
|
|
#ifndef NSS_DISABLE_ECC
|
|
" \"ec\","
|
|
#endif
|
|
" \"rsa\")\n",
|
|
" -k key-type");
|
|
FPS "%-20s The nickname of the key or associated certificate\n",
|
|
" -n name");
|
|
FPS "%-20s Specify the password file\n",
|
|
" -f password-file");
|
|
FPS "%-20s Key database directory (default is ~/.netscape)\n",
|
|
" -d keydir");
|
|
FPS "%-20s Cert & Key database prefix\n",
|
|
" -P dbprefix");
|
|
FPS "%-20s force the database to open R/W\n",
|
|
" -X");
|
|
FPS "\n");
|
|
}
|
|
|
|
static void luL(enum usage_level ul, const char *command)
|
|
{
|
|
int is_my_command = (command && 0 == strcmp(command, "L"));
|
|
if (ul == usage_all || !command || is_my_command)
|
|
FPS "%-15s List all certs, or print out a single named cert (or a subset)\n",
|
|
"-L");
|
|
if (ul == usage_selected && !is_my_command)
|
|
return;
|
|
FPS "%-20s Name of token to search (\"all\" for all tokens)\n",
|
|
" -h token-name ");
|
|
FPS "%-20s Pretty print named cert (list all if unspecified)\n",
|
|
" -n cert-name");
|
|
FPS "%-20s \n"
|
|
"%-20s Pretty print cert with email address (list all if unspecified)\n",
|
|
" --email email-address", "");
|
|
FPS "%-20s Cert database directory (default is ~/.netscape)\n",
|
|
" -d certdir");
|
|
FPS "%-20s Cert & Key database prefix\n",
|
|
" -P dbprefix");
|
|
FPS "%-20s force the database to open R/W\n",
|
|
" -X");
|
|
FPS "%-20s For single cert, print binary DER encoding\n",
|
|
" -r");
|
|
FPS "%-20s For single cert, print ASCII encoding (RFC1113)\n",
|
|
" -a");
|
|
FPS "%-20s \n"
|
|
"%-20s For single cert, print binary DER encoding of extension OID\n",
|
|
" --dump-ext-val OID", "");
|
|
FPS "\n");
|
|
}
|
|
|
|
static void luM(enum usage_level ul, const char *command)
|
|
{
|
|
int is_my_command = (command && 0 == strcmp(command, "M"));
|
|
if (ul == usage_all || !command || is_my_command)
|
|
FPS "%-15s Modify trust attributes of certificate\n",
|
|
"-M");
|
|
if (ul == usage_selected && !is_my_command)
|
|
return;
|
|
FPS "%-20s The nickname of the cert to modify\n",
|
|
" -n cert-name");
|
|
FPS "%-20s Set the certificate trust attributes (see -A above)\n",
|
|
" -t trustargs");
|
|
FPS "%-20s Cert database directory (default is ~/.netscape)\n",
|
|
" -d certdir");
|
|
FPS "%-20s Cert & Key database prefix\n",
|
|
" -P dbprefix");
|
|
FPS "\n");
|
|
}
|
|
|
|
static void luN(enum usage_level ul, const char *command)
|
|
{
|
|
int is_my_command = (command && 0 == strcmp(command, "N"));
|
|
if (ul == usage_all || !command || is_my_command)
|
|
FPS "%-15s Create a new certificate database\n",
|
|
"-N");
|
|
if (ul == usage_selected && !is_my_command)
|
|
return;
|
|
FPS "%-20s Cert database directory (default is ~/.netscape)\n",
|
|
" -d certdir");
|
|
FPS "%-20s Cert & Key database prefix\n",
|
|
" -P dbprefix");
|
|
FPS "%-20s Specify the password file\n",
|
|
" -f password-file");
|
|
FPS "%-20s use empty password when creating a new database\n",
|
|
" --empty-password");
|
|
FPS "\n");
|
|
}
|
|
|
|
static void luT(enum usage_level ul, const char *command)
|
|
{
|
|
int is_my_command = (command && 0 == strcmp(command, "T"));
|
|
if (ul == usage_all || !command || is_my_command)
|
|
FPS "%-15s Reset the Key database or token\n",
|
|
"-T");
|
|
if (ul == usage_selected && !is_my_command)
|
|
return;
|
|
FPS "%-20s Cert database directory (default is ~/.netscape)\n",
|
|
" -d certdir");
|
|
FPS "%-20s Cert & Key database prefix\n",
|
|
" -P dbprefix");
|
|
FPS "%-20s Token to reset (default is internal)\n",
|
|
" -h token-name");
|
|
FPS "%-20s Set token's Site Security Officer password\n",
|
|
" -0 SSO-password");
|
|
FPS "\n");
|
|
}
|
|
|
|
static void luO(enum usage_level ul, const char *command)
|
|
{
|
|
int is_my_command = (command && 0 == strcmp(command, "O"));
|
|
if (ul == usage_all || !command || is_my_command)
|
|
FPS "%-15s Print the chain of a certificate\n",
|
|
"-O");
|
|
if (ul == usage_selected && !is_my_command)
|
|
return;
|
|
FPS "%-20s The nickname of the cert to modify\n",
|
|
" -n cert-name");
|
|
FPS "%-20s Cert database directory (default is ~/.netscape)\n",
|
|
" -d certdir");
|
|
FPS "%-20s Input the certificate in ASCII (RFC1113); default is binary\n",
|
|
" -a");
|
|
FPS "%-20s Cert & Key database prefix\n",
|
|
" -P dbprefix");
|
|
FPS "%-20s force the database to open R/W\n",
|
|
" -X");
|
|
FPS "\n");
|
|
}
|
|
|
|
static void luR(enum usage_level ul, const char *command)
|
|
{
|
|
int is_my_command = (command && 0 == strcmp(command, "R"));
|
|
if (ul == usage_all || !command || is_my_command)
|
|
FPS "%-15s Generate a certificate request (stdout)\n",
|
|
"-R");
|
|
if (ul == usage_selected && !is_my_command)
|
|
return;
|
|
FPS "%-20s Specify the subject name (using RFC1485)\n",
|
|
" -s subject");
|
|
FPS "%-20s Output the cert request to this file\n",
|
|
" -o output-req");
|
|
#ifndef NSS_DISABLE_ECC
|
|
FPS "%-20s Type of key pair to generate (\"dsa\", \"ec\", \"rsa\" (default))\n",
|
|
#else
|
|
FPS "%-20s Type of key pair to generate (\"dsa\", \"rsa\" (default))\n",
|
|
#endif /* NSS_DISABLE_ECC */
|
|
" -k key-type-or-id");
|
|
FPS "%-20s or nickname of the cert key to use \n",
|
|
"");
|
|
FPS "%-20s Name of token in which to generate key (default is internal)\n",
|
|
" -h token-name");
|
|
FPS "%-20s Key size in bits, RSA keys only (min %d, max %d, default %d)\n",
|
|
" -g key-size", MIN_KEY_BITS, MAX_KEY_BITS, DEFAULT_KEY_BITS);
|
|
FPS "%-20s Name of file containing PQG parameters (dsa only)\n",
|
|
" -q pqgfile");
|
|
#ifndef NSS_DISABLE_ECC
|
|
FPS "%-20s Elliptic curve name (ec only)\n",
|
|
" -q curve-name");
|
|
FPS "%-20s See the \"-G\" option for a full list of supported names.\n",
|
|
"");
|
|
#endif /* NSS_DISABLE_ECC */
|
|
FPS "%-20s Specify the password file\n",
|
|
" -f pwfile");
|
|
FPS "%-20s Key database directory (default is ~/.netscape)\n",
|
|
" -d keydir");
|
|
FPS "%-20s Cert & Key database prefix\n",
|
|
" -P dbprefix");
|
|
FPS "%-20s Specify the contact phone number (\"123-456-7890\")\n",
|
|
" -p phone");
|
|
FPS "%-20s \n"
|
|
"%-20s Specify the hash algorithm to use. Possible keywords:\n"
|
|
"%-20s \"MD2\", \"MD4\", \"MD5\", \"SHA1\", \"SHA224\",\n"
|
|
"%-20s \"SHA256\", \"SHA384\", \"SHA512\"\n",
|
|
" -Z hashAlg", "", "", "");
|
|
FPS "%-20s Output the cert request in ASCII (RFC1113); default is binary\n",
|
|
" -a");
|
|
FPS "%-20s \n",
|
|
" See -S for available extension options");
|
|
FPS "%-20s \n",
|
|
" See -G for available key flag options");
|
|
FPS "\n");
|
|
}
|
|
|
|
static void luV(enum usage_level ul, const char *command)
|
|
{
|
|
int is_my_command = (command && 0 == strcmp(command, "V"));
|
|
if (ul == usage_all || !command || is_my_command)
|
|
FPS "%-15s Validate a certificate\n",
|
|
"-V");
|
|
if (ul == usage_selected && !is_my_command)
|
|
return;
|
|
FPS "%-20s The nickname of the cert to Validate\n",
|
|
" -n cert-name");
|
|
FPS "%-20s validity time (\"YYMMDDHHMMSS[+HHMM|-HHMM|Z]\")\n",
|
|
" -b time");
|
|
FPS "%-20s Check certificate signature \n",
|
|
" -e ");
|
|
FPS "%-20s Specify certificate usage:\n", " -u certusage");
|
|
FPS "%-25s C \t SSL Client\n", "");
|
|
FPS "%-25s V \t SSL Server\n", "");
|
|
FPS "%-25s L \t SSL CA\n", "");
|
|
FPS "%-25s A \t Any CA\n", "");
|
|
FPS "%-25s Y \t Verify CA\n", "");
|
|
FPS "%-25s S \t Email signer\n", "");
|
|
FPS "%-25s R \t Email Recipient\n", "");
|
|
FPS "%-25s O \t OCSP status responder\n", "");
|
|
FPS "%-25s J \t Object signer\n", "");
|
|
FPS "%-20s Cert database directory (default is ~/.netscape)\n",
|
|
" -d certdir");
|
|
FPS "%-20s Input the certificate in ASCII (RFC1113); default is binary\n",
|
|
" -a");
|
|
FPS "%-20s Cert & Key database prefix\n",
|
|
" -P dbprefix");
|
|
FPS "%-20s force the database to open R/W\n",
|
|
" -X");
|
|
FPS "\n");
|
|
}
|
|
|
|
static void luW(enum usage_level ul, const char *command)
|
|
{
|
|
int is_my_command = (command && 0 == strcmp(command, "W"));
|
|
if (ul == usage_all || !command || is_my_command)
|
|
FPS "%-15s Change the key database password\n",
|
|
"-W");
|
|
if (ul == usage_selected && !is_my_command)
|
|
return;
|
|
FPS "%-20s cert and key database directory\n",
|
|
" -d certdir");
|
|
FPS "%-20s Specify a file with the current password\n",
|
|
" -f pwfile");
|
|
FPS "%-20s Specify a file with the new password in two lines\n",
|
|
" -@ newpwfile");
|
|
FPS "\n");
|
|
}
|
|
|
|
static void luUpgradeMerge(enum usage_level ul, const char *command)
|
|
{
|
|
int is_my_command = (command && 0 == strcmp(command, "upgrade-merge"));
|
|
if (ul == usage_all || !command || is_my_command)
|
|
FPS "%-15s Upgrade an old database and merge it into a new one\n",
|
|
"--upgrade-merge");
|
|
if (ul == usage_selected && !is_my_command)
|
|
return;
|
|
FPS "%-20s Cert database directory to merge into (default is ~/.netscape)\n",
|
|
" -d certdir");
|
|
FPS "%-20s Cert & Key database prefix of the target database\n",
|
|
" -P dbprefix");
|
|
FPS "%-20s Specify the password file for the target database\n",
|
|
" -f pwfile");
|
|
FPS "%-20s \n%-20s Cert database directory to upgrade from\n",
|
|
" --source-dir certdir", "");
|
|
FPS "%-20s \n%-20s Cert & Key database prefix of the upgrade database\n",
|
|
" --source-prefix dbprefix", "");
|
|
FPS "%-20s \n%-20s Unique identifier for the upgrade database\n",
|
|
" --upgrade-id uniqueID", "");
|
|
FPS "%-20s \n%-20s Name of the token while it is in upgrade state\n",
|
|
" --upgrade-token-name name", "");
|
|
FPS "%-20s Specify the password file for the upgrade database\n",
|
|
" -@ pwfile");
|
|
FPS "\n");
|
|
}
|
|
|
|
static void luMerge(enum usage_level ul, const char *command)
|
|
{
|
|
int is_my_command = (command && 0 == strcmp(command, "merge"));
|
|
if (ul == usage_all || !command || is_my_command)
|
|
FPS "%-15s Merge source database into the target database\n",
|
|
"--merge");
|
|
if (ul == usage_selected && !is_my_command)
|
|
return;
|
|
FPS "%-20s Cert database directory of target (default is ~/.netscape)\n",
|
|
" -d certdir");
|
|
FPS "%-20s Cert & Key database prefix of the target database\n",
|
|
" -P dbprefix");
|
|
FPS "%-20s Specify the password file for the target database\n",
|
|
" -f pwfile");
|
|
FPS "%-20s \n%-20s Cert database directory of the source database\n",
|
|
" --source-dir certdir", "");
|
|
FPS "%-20s \n%-20s Cert & Key database prefix of the source database\n",
|
|
" --source-prefix dbprefix", "");
|
|
FPS "%-20s Specify the password file for the source database\n",
|
|
" -@ pwfile");
|
|
FPS "\n");
|
|
}
|
|
|
|
static void luS(enum usage_level ul, const char *command)
|
|
{
|
|
int is_my_command = (command && 0 == strcmp(command, "S"));
|
|
if (ul == usage_all || !command || is_my_command)
|
|
FPS "%-15s Make a certificate and add to database\n",
|
|
"-S");
|
|
if (ul == usage_selected && !is_my_command)
|
|
return;
|
|
FPS "%-20s Specify the nickname of the cert\n",
|
|
" -n key-name");
|
|
FPS "%-20s Specify the subject name (using RFC1485)\n",
|
|
" -s subject");
|
|
FPS "%-20s The nickname of the issuer cert\n",
|
|
" -c issuer-name");
|
|
FPS "%-20s Set the certificate trust attributes (see -A above)\n",
|
|
" -t trustargs");
|
|
#ifndef NSS_DISABLE_ECC
|
|
FPS "%-20s Type of key pair to generate (\"dsa\", \"ec\", \"rsa\" (default))\n",
|
|
#else
|
|
FPS "%-20s Type of key pair to generate (\"dsa\", \"rsa\" (default))\n",
|
|
#endif /* NSS_DISABLE_ECC */
|
|
" -k key-type-or-id");
|
|
FPS "%-20s Name of token in which to generate key (default is internal)\n",
|
|
" -h token-name");
|
|
FPS "%-20s Key size in bits, RSA keys only (min %d, max %d, default %d)\n",
|
|
" -g key-size", MIN_KEY_BITS, MAX_KEY_BITS, DEFAULT_KEY_BITS);
|
|
FPS "%-20s Name of file containing PQG parameters (dsa only)\n",
|
|
" -q pqgfile");
|
|
#ifndef NSS_DISABLE_ECC
|
|
FPS "%-20s Elliptic curve name (ec only)\n",
|
|
" -q curve-name");
|
|
FPS "%-20s See the \"-G\" option for a full list of supported names.\n",
|
|
"");
|
|
#endif /* NSS_DISABLE_ECC */
|
|
FPS "%-20s Self sign\n",
|
|
" -x");
|
|
FPS "%-20s Cert serial number\n",
|
|
" -m serial-number");
|
|
FPS "%-20s Time Warp\n",
|
|
" -w warp-months");
|
|
FPS "%-20s Months valid (default is 3)\n",
|
|
" -v months-valid");
|
|
FPS "%-20s Specify the password file\n",
|
|
" -f pwfile");
|
|
FPS "%-20s Cert database directory (default is ~/.netscape)\n",
|
|
" -d certdir");
|
|
FPS "%-20s Cert & Key database prefix\n",
|
|
" -P dbprefix");
|
|
FPS "%-20s Specify the contact phone number (\"123-456-7890\")\n",
|
|
" -p phone");
|
|
FPS "%-20s \n"
|
|
"%-20s Specify the hash algorithm to use. Possible keywords:\n"
|
|
"%-20s \"MD2\", \"MD4\", \"MD5\", \"SHA1\", \"SHA224\",\n"
|
|
"%-20s \"SHA256\", \"SHA384\", \"SHA512\"\n",
|
|
" -Z hashAlg", "", "", "");
|
|
FPS "%-20s Create key usage extension\n",
|
|
" -1 ");
|
|
FPS "%-20s Create basic constraint extension\n",
|
|
" -2 ");
|
|
FPS "%-20s Create authority key ID extension\n",
|
|
" -3 ");
|
|
FPS "%-20s Create crl distribution point extension\n",
|
|
" -4 ");
|
|
FPS "%-20s Create netscape cert type extension\n",
|
|
" -5 ");
|
|
FPS "%-20s Create extended key usage extension\n",
|
|
" -6 ");
|
|
FPS "%-20s Create an email subject alt name extension\n",
|
|
" -7 emailAddrs ");
|
|
FPS "%-20s Create a DNS subject alt name extension\n",
|
|
" -8 DNS-names");
|
|
FPS "%-20s Create an Authority Information Access extension\n",
|
|
" --extAIA ");
|
|
FPS "%-20s Create a Subject Information Access extension\n",
|
|
" --extSIA ");
|
|
FPS "%-20s Create a Certificate Policies extension\n",
|
|
" --extCP ");
|
|
FPS "%-20s Create a Policy Mappings extension\n",
|
|
" --extPM ");
|
|
FPS "%-20s Create a Policy Constraints extension\n",
|
|
" --extPC ");
|
|
FPS "%-20s Create an Inhibit Any Policy extension\n",
|
|
" --extIA ");
|
|
FPS "%-20s Create a subject key ID extension\n",
|
|
" --extSKID ");
|
|
FPS "%-20s \n",
|
|
" See -G for available key flag options");
|
|
FPS "%-20s Create a name constraints extension\n",
|
|
" --extNC ");
|
|
FPS "%-20s \n"
|
|
"%-20s Create a Subject Alt Name extension with one or multiple names\n",
|
|
" --extSAN type:name[,type:name]...", "");
|
|
FPS "%-20s - type: directory, dn, dns, edi, ediparty, email, ip, ipaddr,\n", "");
|
|
FPS "%-20s other, registerid, rfc822, uri, x400, x400addr\n", "");
|
|
FPS "%-20s \n"
|
|
"%-20s Add one or multiple extensions that certutil cannot encode yet,\n"
|
|
"%-20s by loading their encodings from external files.\n",
|
|
" --extGeneric OID:critical-flag:filename[,OID:critical-flag:filename]...", "", "");
|
|
FPS "%-20s - OID (example): 1.2.3.4\n", "");
|
|
FPS "%-20s - critical-flag: critical or not-critical\n", "");
|
|
FPS "%-20s - filename: full path to a file containing an encoded extension\n", "");
|
|
FPS "\n");
|
|
}
|
|
|
|
static void LongUsage(char *progName, enum usage_level ul, const char *command)
|
|
{
|
|
luA(ul, command);
|
|
luB(ul, command);
|
|
luE(ul, command);
|
|
luC(ul, command);
|
|
luG(ul, command);
|
|
luD(ul, command);
|
|
luF(ul, command);
|
|
luU(ul, command);
|
|
luK(ul, command);
|
|
luL(ul, command);
|
|
luM(ul, command);
|
|
luN(ul, command);
|
|
luT(ul, command);
|
|
luO(ul, command);
|
|
luR(ul, command);
|
|
luV(ul, command);
|
|
luW(ul, command);
|
|
luUpgradeMerge(ul, command);
|
|
luMerge(ul, command);
|
|
luS(ul, command);
|
|
#undef FPS
|
|
}
|
|
|
|
static void
|
|
Usage(char *progName)
|
|
{
|
|
PR_fprintf(PR_STDERR,
|
|
"%s - Utility to manipulate NSS certificate databases\n\n"
|
|
"Usage: %s <command> -d <database-directory> <options>\n\n"
|
|
"Valid commands:\n", progName, progName);
|
|
LongUsage(progName, usage_selected, NULL);
|
|
PR_fprintf(PR_STDERR, "\n"
|
|
"%s -H <command> : Print available options for the given command\n"
|
|
"%s -H : Print complete help output of all commands and options\n"
|
|
"%s --syntax : Print a short summary of all commands and options\n",
|
|
progName, progName, progName);
|
|
exit(1);
|
|
}
|
|
|
|
static CERTCertificate *
|
|
MakeV1Cert( CERTCertDBHandle * handle,
|
|
CERTCertificateRequest *req,
|
|
char * issuerNickName,
|
|
PRBool selfsign,
|
|
unsigned int serialNumber,
|
|
int warpmonths,
|
|
int validityMonths)
|
|
{
|
|
CERTCertificate *issuerCert = NULL;
|
|
CERTValidity *validity;
|
|
CERTCertificate *cert = NULL;
|
|
PRExplodedTime printableTime;
|
|
PRTime now, after;
|
|
|
|
if ( !selfsign ) {
|
|
issuerCert = CERT_FindCertByNicknameOrEmailAddr(handle, issuerNickName);
|
|
if (!issuerCert) {
|
|
SECU_PrintError(progName, "could not find certificate named \"%s\"",
|
|
issuerNickName);
|
|
return NULL;
|
|
}
|
|
}
|
|
|
|
now = PR_Now();
|
|
PR_ExplodeTime (now, PR_GMTParameters, &printableTime);
|
|
if ( warpmonths ) {
|
|
printableTime.tm_month += warpmonths;
|
|
now = PR_ImplodeTime (&printableTime);
|
|
PR_ExplodeTime (now, PR_GMTParameters, &printableTime);
|
|
}
|
|
printableTime.tm_month += validityMonths;
|
|
after = PR_ImplodeTime (&printableTime);
|
|
|
|
/* note that the time is now in micro-second unit */
|
|
validity = CERT_CreateValidity (now, after);
|
|
if (validity) {
|
|
cert = CERT_CreateCertificate(serialNumber,
|
|
(selfsign ? &req->subject
|
|
: &issuerCert->subject),
|
|
validity, req);
|
|
|
|
CERT_DestroyValidity(validity);
|
|
}
|
|
if ( issuerCert ) {
|
|
CERT_DestroyCertificate (issuerCert);
|
|
}
|
|
|
|
return(cert);
|
|
}
|
|
|
|
static SECStatus
|
|
SignCert(CERTCertDBHandle *handle, CERTCertificate *cert, PRBool selfsign,
|
|
SECOidTag hashAlgTag,
|
|
SECKEYPrivateKey *privKey, char *issuerNickName,
|
|
int certVersion, void *pwarg)
|
|
{
|
|
SECItem der;
|
|
SECKEYPrivateKey *caPrivateKey = NULL;
|
|
SECStatus rv;
|
|
PLArenaPool *arena;
|
|
SECOidTag algID;
|
|
void *dummy;
|
|
|
|
if( !selfsign ) {
|
|
CERTCertificate *issuer = PK11_FindCertFromNickname(issuerNickName, pwarg);
|
|
if( (CERTCertificate *)NULL == issuer ) {
|
|
SECU_PrintError(progName, "unable to find issuer with nickname %s",
|
|
issuerNickName);
|
|
return SECFailure;
|
|
}
|
|
|
|
privKey = caPrivateKey = PK11_FindKeyByAnyCert(issuer, pwarg);
|
|
CERT_DestroyCertificate(issuer);
|
|
if (caPrivateKey == NULL) {
|
|
SECU_PrintError(progName, "unable to retrieve key %s", issuerNickName);
|
|
return SECFailure;
|
|
}
|
|
}
|
|
|
|
arena = cert->arena;
|
|
|
|
algID = SEC_GetSignatureAlgorithmOidTag(privKey->keyType, hashAlgTag);
|
|
if (algID == SEC_OID_UNKNOWN) {
|
|
fprintf(stderr, "Unknown key or hash type for issuer.");
|
|
rv = SECFailure;
|
|
goto done;
|
|
}
|
|
|
|
rv = SECOID_SetAlgorithmID(arena, &cert->signature, algID, 0);
|
|
if (rv != SECSuccess) {
|
|
fprintf(stderr, "Could not set signature algorithm id.");
|
|
goto done;
|
|
}
|
|
|
|
switch(certVersion) {
|
|
case (SEC_CERTIFICATE_VERSION_1):
|
|
/* The initial version for x509 certificates is version one
|
|
* and this default value must be an implicit DER encoding. */
|
|
cert->version.data = NULL;
|
|
cert->version.len = 0;
|
|
break;
|
|
case (SEC_CERTIFICATE_VERSION_2):
|
|
case (SEC_CERTIFICATE_VERSION_3):
|
|
case 3: /* unspecified format (would be version 4 certificate). */
|
|
*(cert->version.data) = certVersion;
|
|
cert->version.len = 1;
|
|
break;
|
|
default:
|
|
PORT_SetError(SEC_ERROR_INVALID_ARGS);
|
|
return SECFailure;
|
|
}
|
|
|
|
der.len = 0;
|
|
der.data = NULL;
|
|
dummy = SEC_ASN1EncodeItem (arena, &der, cert,
|
|
SEC_ASN1_GET(CERT_CertificateTemplate));
|
|
if (!dummy) {
|
|
fprintf (stderr, "Could not encode certificate.\n");
|
|
rv = SECFailure;
|
|
goto done;
|
|
}
|
|
|
|
rv = SEC_DerSignData(arena, &cert->derCert, der.data, der.len, privKey, algID);
|
|
if (rv != SECSuccess) {
|
|
fprintf (stderr, "Could not sign encoded certificate data.\n");
|
|
/* result allocated out of the arena, it will be freed
|
|
* when the arena is freed */
|
|
goto done;
|
|
}
|
|
done:
|
|
if (caPrivateKey) {
|
|
SECKEY_DestroyPrivateKey(caPrivateKey);
|
|
}
|
|
return rv;
|
|
}
|
|
|
|
static SECStatus
|
|
CreateCert(
|
|
CERTCertDBHandle *handle,
|
|
PK11SlotInfo *slot,
|
|
char * issuerNickName,
|
|
const SECItem * certReqDER,
|
|
SECKEYPrivateKey **selfsignprivkey,
|
|
void *pwarg,
|
|
SECOidTag hashAlgTag,
|
|
unsigned int serialNumber,
|
|
int warpmonths,
|
|
int validityMonths,
|
|
const char *emailAddrs,
|
|
const char *dnsNames,
|
|
PRBool ascii,
|
|
PRBool selfsign,
|
|
certutilExtnList extnList,
|
|
const char *extGeneric,
|
|
int certVersion,
|
|
SECItem * certDER)
|
|
{
|
|
void * extHandle;
|
|
CERTCertificate *subjectCert = NULL;
|
|
CERTCertificateRequest *certReq = NULL;
|
|
SECStatus rv = SECSuccess;
|
|
CERTCertExtension **CRexts;
|
|
|
|
do {
|
|
/* Create a certrequest object from the input cert request der */
|
|
certReq = GetCertRequest(certReqDER);
|
|
if (certReq == NULL) {
|
|
GEN_BREAK (SECFailure)
|
|
}
|
|
|
|
subjectCert = MakeV1Cert (handle, certReq, issuerNickName, selfsign,
|
|
serialNumber, warpmonths, validityMonths);
|
|
if (subjectCert == NULL) {
|
|
GEN_BREAK (SECFailure)
|
|
}
|
|
|
|
|
|
extHandle = CERT_StartCertExtensions (subjectCert);
|
|
if (extHandle == NULL) {
|
|
GEN_BREAK (SECFailure)
|
|
}
|
|
|
|
rv = AddExtensions(extHandle, emailAddrs, dnsNames, extnList, extGeneric);
|
|
if (rv != SECSuccess) {
|
|
GEN_BREAK (SECFailure)
|
|
}
|
|
|
|
if (certReq->attributes != NULL &&
|
|
certReq->attributes[0] != NULL &&
|
|
certReq->attributes[0]->attrType.data != NULL &&
|
|
certReq->attributes[0]->attrType.len > 0 &&
|
|
SECOID_FindOIDTag(&certReq->attributes[0]->attrType)
|
|
== SEC_OID_PKCS9_EXTENSION_REQUEST) {
|
|
rv = CERT_GetCertificateRequestExtensions(certReq, &CRexts);
|
|
if (rv != SECSuccess)
|
|
break;
|
|
rv = CERT_MergeExtensions(extHandle, CRexts);
|
|
if (rv != SECSuccess)
|
|
break;
|
|
}
|
|
|
|
CERT_FinishExtensions(extHandle);
|
|
|
|
/* self-signing a cert request, find the private key */
|
|
if (selfsign && *selfsignprivkey == NULL) {
|
|
*selfsignprivkey = PK11_FindKeyByDERCert(slot, subjectCert, pwarg);
|
|
if (!*selfsignprivkey) {
|
|
fprintf(stderr, "Failed to locate private key.\n");
|
|
rv = SECFailure;
|
|
break;
|
|
}
|
|
}
|
|
|
|
rv = SignCert(handle, subjectCert, selfsign, hashAlgTag,
|
|
*selfsignprivkey, issuerNickName,
|
|
certVersion, pwarg);
|
|
if (rv != SECSuccess)
|
|
break;
|
|
|
|
rv = SECFailure;
|
|
if (ascii) {
|
|
char * asciiDER = BTOA_DataToAscii(subjectCert->derCert.data,
|
|
subjectCert->derCert.len);
|
|
if (asciiDER) {
|
|
char * wrapped = PR_smprintf("%s\n%s\n%s\n",
|
|
NS_CERT_HEADER,
|
|
asciiDER,
|
|
NS_CERT_TRAILER);
|
|
if (wrapped) {
|
|
PRUint32 wrappedLen = PL_strlen(wrapped);
|
|
if (SECITEM_AllocItem(NULL, certDER, wrappedLen)) {
|
|
PORT_Memcpy(certDER->data, wrapped, wrappedLen);
|
|
rv = SECSuccess;
|
|
}
|
|
PR_smprintf_free(wrapped);
|
|
}
|
|
PORT_Free(asciiDER);
|
|
}
|
|
} else {
|
|
rv = SECITEM_CopyItem(NULL, certDER, &subjectCert->derCert);
|
|
}
|
|
} while (0);
|
|
CERT_DestroyCertificateRequest (certReq);
|
|
CERT_DestroyCertificate (subjectCert);
|
|
if (rv != SECSuccess) {
|
|
PRErrorCode perr = PR_GetError();
|
|
fprintf(stderr, "%s: unable to create cert (%s)\n", progName,
|
|
SECU_Strerror(perr));
|
|
}
|
|
return (rv);
|
|
}
|
|
|
|
|
|
/*
|
|
* map a class to a user presentable string
|
|
*/
|
|
static const char *objClassArray[] = {
|
|
"Data",
|
|
"Certificate",
|
|
"Public Key",
|
|
"Private Key",
|
|
"Secret Key",
|
|
"Hardware Feature",
|
|
"Domain Parameters",
|
|
"Mechanism"
|
|
};
|
|
|
|
static const char *objNSSClassArray[] = {
|
|
"CKO_NSS",
|
|
"Crl",
|
|
"SMIME Record",
|
|
"Trust",
|
|
"Builtin Root List"
|
|
};
|
|
|
|
|
|
const char *
|
|
getObjectClass(CK_ULONG classType)
|
|
{
|
|
static char buf[sizeof(CK_ULONG)*2+3];
|
|
|
|
if (classType <= CKO_MECHANISM) {
|
|
return objClassArray[classType];
|
|
}
|
|
if (classType >= CKO_NSS && classType <= CKO_NSS_BUILTIN_ROOT_LIST) {
|
|
return objNSSClassArray[classType - CKO_NSS];
|
|
}
|
|
sprintf(buf, "0x%lx", classType);
|
|
return buf;
|
|
}
|
|
|
|
typedef struct {
|
|
char *name;
|
|
int nameSize;
|
|
CK_ULONG value;
|
|
} flagArray;
|
|
|
|
#define NAME_SIZE(x) #x,sizeof(#x)-1
|
|
|
|
flagArray opFlagsArray[] =
|
|
{
|
|
{NAME_SIZE(encrypt), CKF_ENCRYPT},
|
|
{NAME_SIZE(decrypt), CKF_DECRYPT},
|
|
{NAME_SIZE(sign), CKF_SIGN},
|
|
{NAME_SIZE(sign_recover), CKF_SIGN_RECOVER},
|
|
{NAME_SIZE(verify), CKF_VERIFY},
|
|
{NAME_SIZE(verify_recover), CKF_VERIFY_RECOVER},
|
|
{NAME_SIZE(wrap), CKF_WRAP},
|
|
{NAME_SIZE(unwrap), CKF_UNWRAP},
|
|
{NAME_SIZE(derive), CKF_DERIVE},
|
|
};
|
|
|
|
int opFlagsCount = sizeof(opFlagsArray)/sizeof(flagArray);
|
|
|
|
flagArray attrFlagsArray[] =
|
|
{
|
|
{NAME_SIZE(token), PK11_ATTR_TOKEN},
|
|
{NAME_SIZE(session), PK11_ATTR_SESSION},
|
|
{NAME_SIZE(private), PK11_ATTR_PRIVATE},
|
|
{NAME_SIZE(public), PK11_ATTR_PUBLIC},
|
|
{NAME_SIZE(modifiable), PK11_ATTR_MODIFIABLE},
|
|
{NAME_SIZE(unmodifiable), PK11_ATTR_UNMODIFIABLE},
|
|
{NAME_SIZE(sensitive), PK11_ATTR_SENSITIVE},
|
|
{NAME_SIZE(insensitive), PK11_ATTR_INSENSITIVE},
|
|
{NAME_SIZE(extractable), PK11_ATTR_EXTRACTABLE},
|
|
{NAME_SIZE(unextractable), PK11_ATTR_UNEXTRACTABLE}
|
|
|
|
};
|
|
|
|
int attrFlagsCount = sizeof(attrFlagsArray)/sizeof(flagArray);
|
|
|
|
#define MAX_STRING 30
|
|
CK_ULONG
|
|
GetFlags(char *flagsString, flagArray *flagArray, int count)
|
|
{
|
|
CK_ULONG flagsValue = strtol(flagsString, NULL, 0);
|
|
int i;
|
|
|
|
if ((flagsValue != 0) || (*flagsString == 0)) {
|
|
return flagsValue;
|
|
}
|
|
while (*flagsString) {
|
|
for (i=0; i < count; i++) {
|
|
if (strncmp(flagsString, flagArray[i].name, flagArray[i].nameSize)
|
|
== 0) {
|
|
flagsValue |= flagArray[i].value;
|
|
flagsString += flagArray[i].nameSize;
|
|
if (*flagsString != 0) {
|
|
flagsString++;
|
|
}
|
|
break;
|
|
}
|
|
}
|
|
if (i == count) {
|
|
char name[MAX_STRING];
|
|
char *tok;
|
|
|
|
strncpy(name,flagsString, MAX_STRING);
|
|
name[MAX_STRING-1] = 0;
|
|
tok = strchr(name, ',');
|
|
if (tok) {
|
|
*tok = 0;
|
|
}
|
|
fprintf(stderr,"Unknown flag (%s)\n",name);
|
|
tok = strchr(flagsString, ',');
|
|
if (tok == NULL) {
|
|
break;
|
|
}
|
|
flagsString = tok+1;
|
|
}
|
|
}
|
|
return flagsValue;
|
|
}
|
|
|
|
CK_FLAGS
|
|
GetOpFlags(char *flags)
|
|
{
|
|
return GetFlags(flags, opFlagsArray, opFlagsCount);
|
|
}
|
|
|
|
PK11AttrFlags
|
|
GetAttrFlags(char *flags)
|
|
{
|
|
return GetFlags(flags, attrFlagsArray, attrFlagsCount);
|
|
}
|
|
|
|
char *mkNickname(unsigned char *data, int len)
|
|
{
|
|
char *nick = PORT_Alloc(len+1);
|
|
if (!nick) {
|
|
return nick;
|
|
}
|
|
PORT_Memcpy(nick, data, len);
|
|
nick[len] = 0;
|
|
return nick;
|
|
}
|
|
|
|
/*
|
|
* dump a PK11_MergeTokens error log to the console
|
|
*/
|
|
void
|
|
DumpMergeLog(const char *progname, PK11MergeLog *log)
|
|
{
|
|
PK11MergeLogNode *node;
|
|
|
|
for (node = log->head; node; node = node->next) {
|
|
SECItem attrItem;
|
|
char *nickname = NULL;
|
|
const char *objectClass = NULL;
|
|
SECStatus rv;
|
|
|
|
attrItem.data = NULL;
|
|
rv = PK11_ReadRawAttribute(PK11_TypeGeneric, node->object,
|
|
CKA_LABEL, &attrItem);
|
|
if (rv == SECSuccess) {
|
|
nickname = mkNickname(attrItem.data, attrItem.len);
|
|
PORT_Free(attrItem.data);
|
|
}
|
|
attrItem.data = NULL;
|
|
rv = PK11_ReadRawAttribute(PK11_TypeGeneric, node->object,
|
|
CKA_CLASS, &attrItem);
|
|
if (rv == SECSuccess) {
|
|
if (attrItem.len == sizeof(CK_ULONG)) {
|
|
objectClass = getObjectClass(*(CK_ULONG *)attrItem.data);
|
|
}
|
|
PORT_Free(attrItem.data);
|
|
}
|
|
|
|
fprintf(stderr, "%s: Could not merge object %s (type %s): %s\n",
|
|
progName,
|
|
nickname ? nickname : "unnamed",
|
|
objectClass ? objectClass : "unknown",
|
|
SECU_Strerror(node->error));
|
|
|
|
if (nickname) {
|
|
PORT_Free(nickname);
|
|
}
|
|
}
|
|
}
|
|
|
|
/* Certutil commands */
|
|
enum {
|
|
cmd_AddCert = 0,
|
|
cmd_CreateNewCert,
|
|
cmd_DeleteCert,
|
|
cmd_AddEmailCert,
|
|
cmd_DeleteKey,
|
|
cmd_GenKeyPair,
|
|
cmd_PrintHelp,
|
|
cmd_PrintSyntax,
|
|
cmd_ListKeys,
|
|
cmd_ListCerts,
|
|
cmd_ModifyCertTrust,
|
|
cmd_NewDBs,
|
|
cmd_DumpChain,
|
|
cmd_CertReq,
|
|
cmd_CreateAndAddCert,
|
|
cmd_TokenReset,
|
|
cmd_ListModules,
|
|
cmd_CheckCertValidity,
|
|
cmd_ChangePassword,
|
|
cmd_Version,
|
|
cmd_Batch,
|
|
cmd_Merge,
|
|
cmd_UpgradeMerge, /* test only */
|
|
max_cmd
|
|
};
|
|
|
|
/* Certutil options */
|
|
enum certutilOpts {
|
|
opt_SSOPass = 0,
|
|
opt_AddKeyUsageExt,
|
|
opt_AddBasicConstraintExt,
|
|
opt_AddAuthorityKeyIDExt,
|
|
opt_AddCRLDistPtsExt,
|
|
opt_AddNSCertTypeExt,
|
|
opt_AddExtKeyUsageExt,
|
|
opt_ExtendedEmailAddrs,
|
|
opt_ExtendedDNSNames,
|
|
opt_ASCIIForIO,
|
|
opt_ValidityTime,
|
|
opt_IssuerName,
|
|
opt_CertDir,
|
|
opt_VerifySig,
|
|
opt_PasswordFile,
|
|
opt_KeySize,
|
|
opt_TokenName,
|
|
opt_InputFile,
|
|
opt_Emailaddress,
|
|
opt_KeyIndex,
|
|
opt_KeyType,
|
|
opt_DetailedInfo,
|
|
opt_SerialNumber,
|
|
opt_Nickname,
|
|
opt_OutputFile,
|
|
opt_PhoneNumber,
|
|
opt_DBPrefix,
|
|
opt_PQGFile,
|
|
opt_BinaryDER,
|
|
opt_Subject,
|
|
opt_Trust,
|
|
opt_Usage,
|
|
opt_Validity,
|
|
opt_OffsetMonths,
|
|
opt_SelfSign,
|
|
opt_RW,
|
|
opt_Exponent,
|
|
opt_NoiseFile,
|
|
opt_Hash,
|
|
opt_NewPasswordFile,
|
|
opt_AddAuthInfoAccExt,
|
|
opt_AddSubjInfoAccExt,
|
|
opt_AddCertPoliciesExt,
|
|
opt_AddPolicyMapExt,
|
|
opt_AddPolicyConstrExt,
|
|
opt_AddInhibAnyExt,
|
|
opt_AddNameConstraintsExt,
|
|
opt_AddSubjectKeyIDExt,
|
|
opt_AddCmdKeyUsageExt,
|
|
opt_AddCmdNSCertTypeExt,
|
|
opt_AddCmdExtKeyUsageExt,
|
|
opt_SourceDir,
|
|
opt_SourcePrefix,
|
|
opt_UpgradeID,
|
|
opt_UpgradeTokenName,
|
|
opt_KeyOpFlagsOn,
|
|
opt_KeyOpFlagsOff,
|
|
opt_KeyAttrFlags,
|
|
opt_EmptyPassword,
|
|
opt_CertVersion,
|
|
opt_AddSubjectAltNameExt,
|
|
opt_DumpExtensionValue,
|
|
opt_GenericExtensions,
|
|
opt_Help
|
|
};
|
|
|
|
static const
|
|
secuCommandFlag commands_init[] =
|
|
{
|
|
{ /* cmd_AddCert */ 'A', PR_FALSE, 0, PR_FALSE },
|
|
{ /* cmd_CreateNewCert */ 'C', PR_FALSE, 0, PR_FALSE },
|
|
{ /* cmd_DeleteCert */ 'D', PR_FALSE, 0, PR_FALSE },
|
|
{ /* cmd_AddEmailCert */ 'E', PR_FALSE, 0, PR_FALSE },
|
|
{ /* cmd_DeleteKey */ 'F', PR_FALSE, 0, PR_FALSE },
|
|
{ /* cmd_GenKeyPair */ 'G', PR_FALSE, 0, PR_FALSE },
|
|
{ /* cmd_PrintHelp */ 'H', PR_FALSE, 0, PR_FALSE, "help" },
|
|
{ /* cmd_PrintSyntax */ 0, PR_FALSE, 0, PR_FALSE,
|
|
"syntax" },
|
|
{ /* cmd_ListKeys */ 'K', PR_FALSE, 0, PR_FALSE },
|
|
{ /* cmd_ListCerts */ 'L', PR_FALSE, 0, PR_FALSE },
|
|
{ /* cmd_ModifyCertTrust */ 'M', PR_FALSE, 0, PR_FALSE },
|
|
{ /* cmd_NewDBs */ 'N', PR_FALSE, 0, PR_FALSE },
|
|
{ /* cmd_DumpChain */ 'O', PR_FALSE, 0, PR_FALSE },
|
|
{ /* cmd_CertReq */ 'R', PR_FALSE, 0, PR_FALSE },
|
|
{ /* cmd_CreateAndAddCert */ 'S', PR_FALSE, 0, PR_FALSE },
|
|
{ /* cmd_TokenReset */ 'T', PR_FALSE, 0, PR_FALSE },
|
|
{ /* cmd_ListModules */ 'U', PR_FALSE, 0, PR_FALSE },
|
|
{ /* cmd_CheckCertValidity */ 'V', PR_FALSE, 0, PR_FALSE },
|
|
{ /* cmd_ChangePassword */ 'W', PR_FALSE, 0, PR_FALSE },
|
|
{ /* cmd_Version */ 'Y', PR_FALSE, 0, PR_FALSE },
|
|
{ /* cmd_Batch */ 'B', PR_FALSE, 0, PR_FALSE },
|
|
{ /* cmd_Merge */ 0, PR_FALSE, 0, PR_FALSE, "merge" },
|
|
{ /* cmd_UpgradeMerge */ 0, PR_FALSE, 0, PR_FALSE,
|
|
"upgrade-merge" }
|
|
};
|
|
#define NUM_COMMANDS ((sizeof commands_init) / (sizeof commands_init[0]))
|
|
|
|
static const
|
|
secuCommandFlag options_init[] =
|
|
{
|
|
{ /* opt_SSOPass */ '0', PR_TRUE, 0, PR_FALSE },
|
|
{ /* opt_AddKeyUsageExt */ '1', PR_FALSE, 0, PR_FALSE },
|
|
{ /* opt_AddBasicConstraintExt*/ '2', PR_FALSE, 0, PR_FALSE },
|
|
{ /* opt_AddAuthorityKeyIDExt*/ '3', PR_FALSE, 0, PR_FALSE },
|
|
{ /* opt_AddCRLDistPtsExt */ '4', PR_FALSE, 0, PR_FALSE },
|
|
{ /* opt_AddNSCertTypeExt */ '5', PR_FALSE, 0, PR_FALSE },
|
|
{ /* opt_AddExtKeyUsageExt */ '6', PR_FALSE, 0, PR_FALSE },
|
|
{ /* opt_ExtendedEmailAddrs */ '7', PR_TRUE, 0, PR_FALSE },
|
|
{ /* opt_ExtendedDNSNames */ '8', PR_TRUE, 0, PR_FALSE },
|
|
{ /* opt_ASCIIForIO */ 'a', PR_FALSE, 0, PR_FALSE },
|
|
{ /* opt_ValidityTime */ 'b', PR_TRUE, 0, PR_FALSE },
|
|
{ /* opt_IssuerName */ 'c', PR_TRUE, 0, PR_FALSE },
|
|
{ /* opt_CertDir */ 'd', PR_TRUE, 0, PR_FALSE },
|
|
{ /* opt_VerifySig */ 'e', PR_FALSE, 0, PR_FALSE },
|
|
{ /* opt_PasswordFile */ 'f', PR_TRUE, 0, PR_FALSE },
|
|
{ /* opt_KeySize */ 'g', PR_TRUE, 0, PR_FALSE },
|
|
{ /* opt_TokenName */ 'h', PR_TRUE, 0, PR_FALSE },
|
|
{ /* opt_InputFile */ 'i', PR_TRUE, 0, PR_FALSE },
|
|
{ /* opt_Emailaddress */ 0, PR_TRUE, 0, PR_FALSE, "email" },
|
|
{ /* opt_KeyIndex */ 'j', PR_TRUE, 0, PR_FALSE },
|
|
{ /* opt_KeyType */ 'k', PR_TRUE, 0, PR_FALSE },
|
|
{ /* opt_DetailedInfo */ 'l', PR_FALSE, 0, PR_FALSE },
|
|
{ /* opt_SerialNumber */ 'm', PR_TRUE, 0, PR_FALSE },
|
|
{ /* opt_Nickname */ 'n', PR_TRUE, 0, PR_FALSE },
|
|
{ /* opt_OutputFile */ 'o', PR_TRUE, 0, PR_FALSE },
|
|
{ /* opt_PhoneNumber */ 'p', PR_TRUE, 0, PR_FALSE },
|
|
{ /* opt_DBPrefix */ 'P', PR_TRUE, 0, PR_FALSE },
|
|
{ /* opt_PQGFile */ 'q', PR_TRUE, 0, PR_FALSE },
|
|
{ /* opt_BinaryDER */ 'r', PR_FALSE, 0, PR_FALSE },
|
|
{ /* opt_Subject */ 's', PR_TRUE, 0, PR_FALSE },
|
|
{ /* opt_Trust */ 't', PR_TRUE, 0, PR_FALSE },
|
|
{ /* opt_Usage */ 'u', PR_TRUE, 0, PR_FALSE },
|
|
{ /* opt_Validity */ 'v', PR_TRUE, 0, PR_FALSE },
|
|
{ /* opt_OffsetMonths */ 'w', PR_TRUE, 0, PR_FALSE },
|
|
{ /* opt_SelfSign */ 'x', PR_FALSE, 0, PR_FALSE },
|
|
{ /* opt_RW */ 'X', PR_FALSE, 0, PR_FALSE },
|
|
{ /* opt_Exponent */ 'y', PR_TRUE, 0, PR_FALSE },
|
|
{ /* opt_NoiseFile */ 'z', PR_TRUE, 0, PR_FALSE },
|
|
{ /* opt_Hash */ 'Z', PR_TRUE, 0, PR_FALSE },
|
|
{ /* opt_NewPasswordFile */ '@', PR_TRUE, 0, PR_FALSE },
|
|
{ /* opt_AddAuthInfoAccExt */ 0, PR_FALSE, 0, PR_FALSE, "extAIA" },
|
|
{ /* opt_AddSubjInfoAccExt */ 0, PR_FALSE, 0, PR_FALSE, "extSIA" },
|
|
{ /* opt_AddCertPoliciesExt */ 0, PR_FALSE, 0, PR_FALSE, "extCP" },
|
|
{ /* opt_AddPolicyMapExt */ 0, PR_FALSE, 0, PR_FALSE, "extPM" },
|
|
{ /* opt_AddPolicyConstrExt */ 0, PR_FALSE, 0, PR_FALSE, "extPC" },
|
|
{ /* opt_AddInhibAnyExt */ 0, PR_FALSE, 0, PR_FALSE, "extIA" },
|
|
{ /* opt_AddNameConstraintsExt*/ 0, PR_FALSE, 0, PR_FALSE, "extNC" },
|
|
{ /* opt_AddSubjectKeyIDExt */ 0, PR_FALSE, 0, PR_FALSE,
|
|
"extSKID" },
|
|
{ /* opt_AddCmdKeyUsageExt */ 0, PR_TRUE, 0, PR_FALSE,
|
|
"keyUsage" },
|
|
{ /* opt_AddCmdNSCertTypeExt */ 0, PR_TRUE, 0, PR_FALSE,
|
|
"nsCertType" },
|
|
{ /* opt_AddCmdExtKeyUsageExt*/ 0, PR_TRUE, 0, PR_FALSE,
|
|
"extKeyUsage" },
|
|
|
|
{ /* opt_SourceDir */ 0, PR_TRUE, 0, PR_FALSE,
|
|
"source-dir"},
|
|
{ /* opt_SourcePrefix */ 0, PR_TRUE, 0, PR_FALSE,
|
|
"source-prefix"},
|
|
{ /* opt_UpgradeID */ 0, PR_TRUE, 0, PR_FALSE,
|
|
"upgrade-id"},
|
|
{ /* opt_UpgradeTokenName */ 0, PR_TRUE, 0, PR_FALSE,
|
|
"upgrade-token-name"},
|
|
{ /* opt_KeyOpFlagsOn */ 0, PR_TRUE, 0, PR_FALSE,
|
|
"keyOpFlagsOn"},
|
|
{ /* opt_KeyOpFlagsOff */ 0, PR_TRUE, 0, PR_FALSE,
|
|
"keyOpFlagsOff"},
|
|
{ /* opt_KeyAttrFlags */ 0, PR_TRUE, 0, PR_FALSE,
|
|
"keyAttrFlags"},
|
|
{ /* opt_EmptyPassword */ 0, PR_FALSE, 0, PR_FALSE,
|
|
"empty-password"},
|
|
{ /* opt_CertVersion */ 0, PR_TRUE, 0, PR_FALSE,
|
|
"certVersion"},
|
|
{ /* opt_AddSubjectAltExt */ 0, PR_TRUE, 0, PR_FALSE, "extSAN"},
|
|
{ /* opt_DumpExtensionValue */ 0, PR_TRUE, 0, PR_FALSE,
|
|
"dump-ext-val"},
|
|
{ /* opt_GenericExtensions */ 0, PR_TRUE, 0, PR_FALSE,
|
|
"extGeneric"},
|
|
};
|
|
#define NUM_OPTIONS ((sizeof options_init) / (sizeof options_init[0]))
|
|
|
|
static secuCommandFlag certutil_commands[NUM_COMMANDS];
|
|
static secuCommandFlag certutil_options [NUM_OPTIONS ];
|
|
|
|
static const secuCommand certutil = {
|
|
NUM_COMMANDS,
|
|
NUM_OPTIONS,
|
|
certutil_commands,
|
|
certutil_options
|
|
};
|
|
|
|
static certutilExtnList certutil_extns;
|
|
|
|
static int
|
|
certutil_main(int argc, char **argv, PRBool initialize)
|
|
{
|
|
CERTCertDBHandle *certHandle;
|
|
PK11SlotInfo *slot = NULL;
|
|
CERTName * subject = 0;
|
|
PRFileDesc *inFile = PR_STDIN;
|
|
PRFileDesc *outFile = PR_STDOUT;
|
|
SECItem certReqDER = { siBuffer, NULL, 0 };
|
|
SECItem certDER = { siBuffer, NULL, 0 };
|
|
char * slotname = "internal";
|
|
char * certPrefix = "";
|
|
char * sourceDir = "";
|
|
char * srcCertPrefix = "";
|
|
char * upgradeID = "";
|
|
char * upgradeTokenName = "";
|
|
KeyType keytype = rsaKey;
|
|
char * name = NULL;
|
|
char * email = NULL;
|
|
char * keysource = NULL;
|
|
SECOidTag hashAlgTag = SEC_OID_UNKNOWN;
|
|
int keysize = DEFAULT_KEY_BITS;
|
|
int publicExponent = 0x010001;
|
|
int certVersion = SEC_CERTIFICATE_VERSION_3;
|
|
unsigned int serialNumber = 0;
|
|
int warpmonths = 0;
|
|
int validityMonths = 3;
|
|
int commandsEntered = 0;
|
|
char commandToRun = '\0';
|
|
secuPWData pwdata = { PW_NONE, 0 };
|
|
secuPWData pwdata2 = { PW_NONE, 0 };
|
|
PRBool readOnly = PR_FALSE;
|
|
PRBool initialized = PR_FALSE;
|
|
CK_FLAGS keyOpFlagsOn = 0;
|
|
CK_FLAGS keyOpFlagsOff = 0;
|
|
PK11AttrFlags keyAttrFlags =
|
|
PK11_ATTR_TOKEN | PK11_ATTR_SENSITIVE | PK11_ATTR_PRIVATE;
|
|
|
|
SECKEYPrivateKey *privkey = NULL;
|
|
SECKEYPublicKey *pubkey = NULL;
|
|
|
|
int i;
|
|
SECStatus rv;
|
|
|
|
progName = PORT_Strrchr(argv[0], '/');
|
|
progName = progName ? progName+1 : argv[0];
|
|
memcpy(certutil_commands, commands_init, sizeof commands_init);
|
|
memcpy(certutil_options, options_init, sizeof options_init);
|
|
|
|
rv = SECU_ParseCommandLine(argc, argv, progName, &certutil);
|
|
|
|
if (rv != SECSuccess)
|
|
Usage(progName);
|
|
|
|
if (certutil.commands[cmd_PrintSyntax].activated) {
|
|
PrintSyntax(progName);
|
|
}
|
|
|
|
if (certutil.commands[cmd_PrintHelp].activated) {
|
|
int i;
|
|
char buf[2];
|
|
const char *command = NULL;
|
|
for (i = 0; i < max_cmd; i++) {
|
|
if (i == cmd_PrintHelp)
|
|
continue;
|
|
if (certutil.commands[i].activated) {
|
|
if (certutil.commands[i].flag) {
|
|
buf[0] = certutil.commands[i].flag;
|
|
buf[1] = 0;
|
|
command = buf;
|
|
}
|
|
else {
|
|
command = certutil.commands[i].longform;
|
|
}
|
|
break;
|
|
}
|
|
}
|
|
LongUsage(progName, (command ? usage_selected : usage_all), command);
|
|
exit(1);
|
|
}
|
|
|
|
if (certutil.options[opt_PasswordFile].arg) {
|
|
pwdata.source = PW_FROMFILE;
|
|
pwdata.data = certutil.options[opt_PasswordFile].arg;
|
|
}
|
|
if (certutil.options[opt_NewPasswordFile].arg) {
|
|
pwdata2.source = PW_FROMFILE;
|
|
pwdata2.data = certutil.options[opt_NewPasswordFile].arg;
|
|
}
|
|
|
|
if (certutil.options[opt_CertDir].activated)
|
|
SECU_ConfigDirectory(certutil.options[opt_CertDir].arg);
|
|
|
|
if (certutil.options[opt_SourceDir].activated)
|
|
sourceDir = certutil.options[opt_SourceDir].arg;
|
|
|
|
if (certutil.options[opt_UpgradeID].activated)
|
|
upgradeID = certutil.options[opt_UpgradeID].arg;
|
|
|
|
if (certutil.options[opt_UpgradeTokenName].activated)
|
|
upgradeTokenName = certutil.options[opt_UpgradeTokenName].arg;
|
|
|
|
if (certutil.options[opt_KeySize].activated) {
|
|
keysize = PORT_Atoi(certutil.options[opt_KeySize].arg);
|
|
if ((keysize < MIN_KEY_BITS) || (keysize > MAX_KEY_BITS)) {
|
|
PR_fprintf(PR_STDERR,
|
|
"%s -g: Keysize must be between %d and %d.\n",
|
|
progName, MIN_KEY_BITS, MAX_KEY_BITS);
|
|
return 255;
|
|
}
|
|
#ifndef NSS_DISABLE_ECC
|
|
if (keytype == ecKey) {
|
|
PR_fprintf(PR_STDERR, "%s -g: Not for ec keys.\n", progName);
|
|
return 255;
|
|
}
|
|
#endif /* NSS_DISABLE_ECC */
|
|
|
|
}
|
|
|
|
/* -h specify token name */
|
|
if (certutil.options[opt_TokenName].activated) {
|
|
if (PL_strcmp(certutil.options[opt_TokenName].arg, "all") == 0)
|
|
slotname = NULL;
|
|
else
|
|
slotname = PL_strdup(certutil.options[opt_TokenName].arg);
|
|
}
|
|
|
|
/* -Z hash type */
|
|
if (certutil.options[opt_Hash].activated) {
|
|
char * arg = certutil.options[opt_Hash].arg;
|
|
hashAlgTag = SECU_StringToSignatureAlgTag(arg);
|
|
if (hashAlgTag == SEC_OID_UNKNOWN) {
|
|
PR_fprintf(PR_STDERR, "%s -Z: %s is not a recognized type.\n",
|
|
progName, arg);
|
|
return 255;
|
|
}
|
|
}
|
|
|
|
/* -k key type */
|
|
if (certutil.options[opt_KeyType].activated) {
|
|
char * arg = certutil.options[opt_KeyType].arg;
|
|
if (PL_strcmp(arg, "rsa") == 0) {
|
|
keytype = rsaKey;
|
|
} else if (PL_strcmp(arg, "dsa") == 0) {
|
|
keytype = dsaKey;
|
|
#ifndef NSS_DISABLE_ECC
|
|
} else if (PL_strcmp(arg, "ec") == 0) {
|
|
keytype = ecKey;
|
|
#endif /* NSS_DISABLE_ECC */
|
|
} else if (PL_strcmp(arg, "all") == 0) {
|
|
keytype = nullKey;
|
|
} else {
|
|
/* use an existing private/public key pair */
|
|
keysource = arg;
|
|
}
|
|
} else if (certutil.commands[cmd_ListKeys].activated) {
|
|
keytype = nullKey;
|
|
}
|
|
|
|
if (certutil.options[opt_KeyOpFlagsOn].activated) {
|
|
keyOpFlagsOn = GetOpFlags(certutil.options[opt_KeyOpFlagsOn].arg);
|
|
}
|
|
if (certutil.options[opt_KeyOpFlagsOff].activated) {
|
|
keyOpFlagsOff = GetOpFlags(certutil.options[opt_KeyOpFlagsOff].arg);
|
|
keyOpFlagsOn &=~keyOpFlagsOff; /* make off override on */
|
|
}
|
|
if (certutil.options[opt_KeyAttrFlags].activated) {
|
|
keyAttrFlags = GetAttrFlags(certutil.options[opt_KeyAttrFlags].arg);
|
|
}
|
|
|
|
/* -m serial number */
|
|
if (certutil.options[opt_SerialNumber].activated) {
|
|
int sn = PORT_Atoi(certutil.options[opt_SerialNumber].arg);
|
|
if (sn < 0) {
|
|
PR_fprintf(PR_STDERR, "%s -m: %s is not a valid serial number.\n",
|
|
progName, certutil.options[opt_SerialNumber].arg);
|
|
return 255;
|
|
}
|
|
serialNumber = sn;
|
|
}
|
|
|
|
/* -P certdb name prefix */
|
|
if (certutil.options[opt_DBPrefix].activated) {
|
|
if (certutil.options[opt_DBPrefix].arg) {
|
|
certPrefix = strdup(certutil.options[opt_DBPrefix].arg);
|
|
} else {
|
|
Usage(progName);
|
|
}
|
|
}
|
|
|
|
/* --source-prefix certdb name prefix */
|
|
if (certutil.options[opt_SourcePrefix].activated) {
|
|
if (certutil.options[opt_SourcePrefix].arg) {
|
|
srcCertPrefix = strdup(certutil.options[opt_SourcePrefix].arg);
|
|
} else {
|
|
Usage(progName);
|
|
}
|
|
}
|
|
|
|
/* -q PQG file or curve name */
|
|
if (certutil.options[opt_PQGFile].activated) {
|
|
#ifndef NSS_DISABLE_ECC
|
|
if ((keytype != dsaKey) && (keytype != ecKey)) {
|
|
PR_fprintf(PR_STDERR, "%s -q: specifies a PQG file for DSA keys" \
|
|
" (-k dsa) or a named curve for EC keys (-k ec)\n)",
|
|
progName);
|
|
#else /* } */
|
|
if (keytype != dsaKey) {
|
|
PR_fprintf(PR_STDERR, "%s -q: PQG file is for DSA key (-k dsa).\n)",
|
|
progName);
|
|
#endif /* NSS_DISABLE_ECC */
|
|
return 255;
|
|
}
|
|
}
|
|
|
|
/* -s subject name */
|
|
if (certutil.options[opt_Subject].activated) {
|
|
subject = CERT_AsciiToName(certutil.options[opt_Subject].arg);
|
|
if (!subject) {
|
|
PR_fprintf(PR_STDERR, "%s -s: improperly formatted name: \"%s\"\n",
|
|
progName, certutil.options[opt_Subject].arg);
|
|
return 255;
|
|
}
|
|
}
|
|
|
|
/* -v validity period */
|
|
if (certutil.options[opt_Validity].activated) {
|
|
validityMonths = PORT_Atoi(certutil.options[opt_Validity].arg);
|
|
if (validityMonths < 0) {
|
|
PR_fprintf(PR_STDERR, "%s -v: incorrect validity period: \"%s\"\n",
|
|
progName, certutil.options[opt_Validity].arg);
|
|
return 255;
|
|
}
|
|
}
|
|
|
|
/* -w warp months */
|
|
if (certutil.options[opt_OffsetMonths].activated)
|
|
warpmonths = PORT_Atoi(certutil.options[opt_OffsetMonths].arg);
|
|
|
|
/* -y public exponent (for RSA) */
|
|
if (certutil.options[opt_Exponent].activated) {
|
|
publicExponent = PORT_Atoi(certutil.options[opt_Exponent].arg);
|
|
if ((publicExponent != 3) &&
|
|
(publicExponent != 17) &&
|
|
(publicExponent != 65537)) {
|
|
PR_fprintf(PR_STDERR, "%s -y: incorrect public exponent %d.",
|
|
progName, publicExponent);
|
|
PR_fprintf(PR_STDERR, "Must be 3, 17, or 65537.\n");
|
|
return 255;
|
|
}
|
|
}
|
|
|
|
/* --certVersion */
|
|
if (certutil.options[opt_CertVersion].activated) {
|
|
certVersion = PORT_Atoi(certutil.options[opt_CertVersion].arg);
|
|
if (certVersion < 1 || certVersion > 4) {
|
|
PR_fprintf(PR_STDERR, "%s -certVersion: incorrect certificate version %d.",
|
|
progName, certVersion);
|
|
PR_fprintf(PR_STDERR, "Must be 1, 2, 3 or 4.\n");
|
|
return 255;
|
|
}
|
|
certVersion = certVersion - 1;
|
|
}
|
|
|
|
|
|
/* Check number of commands entered. */
|
|
commandsEntered = 0;
|
|
for (i=0; i< certutil.numCommands; i++) {
|
|
if (certutil.commands[i].activated) {
|
|
commandToRun = certutil.commands[i].flag;
|
|
commandsEntered++;
|
|
}
|
|
if (commandsEntered > 1)
|
|
break;
|
|
}
|
|
if (commandsEntered > 1) {
|
|
PR_fprintf(PR_STDERR, "%s: only one command at a time!\n", progName);
|
|
PR_fprintf(PR_STDERR, "You entered: ");
|
|
for (i=0; i< certutil.numCommands; i++) {
|
|
if (certutil.commands[i].activated)
|
|
PR_fprintf(PR_STDERR, " -%c", certutil.commands[i].flag);
|
|
}
|
|
PR_fprintf(PR_STDERR, "\n");
|
|
return 255;
|
|
}
|
|
if (commandsEntered == 0) {
|
|
Usage(progName);
|
|
}
|
|
|
|
if (certutil.commands[cmd_ListCerts].activated ||
|
|
certutil.commands[cmd_PrintHelp].activated ||
|
|
certutil.commands[cmd_ListKeys].activated ||
|
|
certutil.commands[cmd_ListModules].activated ||
|
|
certutil.commands[cmd_CheckCertValidity].activated ||
|
|
certutil.commands[cmd_Version].activated ) {
|
|
readOnly = !certutil.options[opt_RW].activated;
|
|
}
|
|
|
|
/* -A, -D, -F, -M, -S, -V, and all require -n */
|
|
if ((certutil.commands[cmd_AddCert].activated ||
|
|
certutil.commands[cmd_DeleteCert].activated ||
|
|
certutil.commands[cmd_DeleteKey].activated ||
|
|
certutil.commands[cmd_DumpChain].activated ||
|
|
certutil.commands[cmd_ModifyCertTrust].activated ||
|
|
certutil.commands[cmd_CreateAndAddCert].activated ||
|
|
certutil.commands[cmd_CheckCertValidity].activated) &&
|
|
!certutil.options[opt_Nickname].activated) {
|
|
PR_fprintf(PR_STDERR,
|
|
"%s -%c: nickname is required for this command (-n).\n",
|
|
progName, commandToRun);
|
|
return 255;
|
|
}
|
|
|
|
/* -A, -E, -M, -S require trust */
|
|
if ((certutil.commands[cmd_AddCert].activated ||
|
|
certutil.commands[cmd_AddEmailCert].activated ||
|
|
certutil.commands[cmd_ModifyCertTrust].activated ||
|
|
certutil.commands[cmd_CreateAndAddCert].activated) &&
|
|
!certutil.options[opt_Trust].activated) {
|
|
PR_fprintf(PR_STDERR,
|
|
"%s -%c: trust is required for this command (-t).\n",
|
|
progName, commandToRun);
|
|
return 255;
|
|
}
|
|
|
|
/* if -L is given raw, ascii or dump mode, it must be for only one cert. */
|
|
if (certutil.commands[cmd_ListCerts].activated &&
|
|
(certutil.options[opt_ASCIIForIO].activated ||
|
|
certutil.options[opt_DumpExtensionValue].activated ||
|
|
certutil.options[opt_BinaryDER].activated) &&
|
|
!certutil.options[opt_Nickname].activated) {
|
|
PR_fprintf(PR_STDERR,
|
|
"%s: nickname is required to dump cert in raw or ascii mode.\n",
|
|
progName);
|
|
return 255;
|
|
}
|
|
|
|
/* -L can only be in (raw || ascii). */
|
|
if (certutil.commands[cmd_ListCerts].activated &&
|
|
certutil.options[opt_ASCIIForIO].activated &&
|
|
certutil.options[opt_BinaryDER].activated) {
|
|
PR_fprintf(PR_STDERR,
|
|
"%s: cannot specify both -r and -a when dumping cert.\n",
|
|
progName);
|
|
return 255;
|
|
}
|
|
|
|
/* If making a cert request, need a subject. */
|
|
if ((certutil.commands[cmd_CertReq].activated ||
|
|
certutil.commands[cmd_CreateAndAddCert].activated) &&
|
|
!(certutil.options[opt_Subject].activated || keysource)) {
|
|
PR_fprintf(PR_STDERR,
|
|
"%s -%c: subject is required to create a cert request.\n",
|
|
progName, commandToRun);
|
|
return 255;
|
|
}
|
|
|
|
/* If making a cert, need a serial number. */
|
|
if ((certutil.commands[cmd_CreateNewCert].activated ||
|
|
certutil.commands[cmd_CreateAndAddCert].activated) &&
|
|
!certutil.options[opt_SerialNumber].activated) {
|
|
/* Make a default serial number from the current time. */
|
|
PRTime now = PR_Now();
|
|
LL_USHR(now, now, 19);
|
|
LL_L2UI(serialNumber, now);
|
|
}
|
|
|
|
/* Validation needs the usage to validate for. */
|
|
if (certutil.commands[cmd_CheckCertValidity].activated &&
|
|
!certutil.options[opt_Usage].activated) {
|
|
PR_fprintf(PR_STDERR,
|
|
"%s -V: specify a usage to validate the cert for (-u).\n",
|
|
progName);
|
|
return 255;
|
|
}
|
|
|
|
/* Upgrade/Merge needs a source database and a upgrade id. */
|
|
if (certutil.commands[cmd_UpgradeMerge].activated &&
|
|
!(certutil.options[opt_SourceDir].activated &&
|
|
certutil.options[opt_UpgradeID].activated)) {
|
|
|
|
PR_fprintf(PR_STDERR,
|
|
"%s --upgrade-merge: specify an upgrade database directory "
|
|
"(--source-dir) and\n"
|
|
" an upgrade ID (--upgrade-id).\n",
|
|
progName);
|
|
return 255;
|
|
}
|
|
|
|
/* Merge needs a source database */
|
|
if (certutil.commands[cmd_Merge].activated &&
|
|
!certutil.options[opt_SourceDir].activated) {
|
|
|
|
|
|
PR_fprintf(PR_STDERR,
|
|
"%s --merge: specify an source database directory "
|
|
"(--source-dir)\n",
|
|
progName);
|
|
return 255;
|
|
}
|
|
|
|
|
|
/* To make a cert, need either a issuer or to self-sign it. */
|
|
if (certutil.commands[cmd_CreateAndAddCert].activated &&
|
|
!(certutil.options[opt_IssuerName].activated ||
|
|
certutil.options[opt_SelfSign].activated)) {
|
|
PR_fprintf(PR_STDERR,
|
|
"%s -S: must specify issuer (-c) or self-sign (-x).\n",
|
|
progName);
|
|
return 255;
|
|
}
|
|
|
|
/* Using slotname == NULL for listing keys and certs on all slots,
|
|
* but only that. */
|
|
if (!(certutil.commands[cmd_ListKeys].activated ||
|
|
certutil.commands[cmd_DumpChain].activated ||
|
|
certutil.commands[cmd_ListCerts].activated) && slotname == NULL) {
|
|
PR_fprintf(PR_STDERR,
|
|
"%s -%c: cannot use \"-h all\" for this command.\n",
|
|
progName, commandToRun);
|
|
return 255;
|
|
}
|
|
|
|
/* Using keytype == nullKey for list all key types, but only that. */
|
|
if (!certutil.commands[cmd_ListKeys].activated && keytype == nullKey) {
|
|
PR_fprintf(PR_STDERR,
|
|
"%s -%c: cannot use \"-k all\" for this command.\n",
|
|
progName, commandToRun);
|
|
return 255;
|
|
}
|
|
|
|
/* Open the input file. */
|
|
if (certutil.options[opt_InputFile].activated) {
|
|
inFile = PR_Open(certutil.options[opt_InputFile].arg, PR_RDONLY, 0);
|
|
if (!inFile) {
|
|
PR_fprintf(PR_STDERR,
|
|
"%s: unable to open \"%s\" for reading (%ld, %ld).\n",
|
|
progName, certutil.options[opt_InputFile].arg,
|
|
PR_GetError(), PR_GetOSError());
|
|
return 255;
|
|
}
|
|
}
|
|
|
|
/* Open the output file. */
|
|
if (certutil.options[opt_OutputFile].activated) {
|
|
outFile = PR_Open(certutil.options[opt_OutputFile].arg,
|
|
PR_CREATE_FILE | PR_RDWR | PR_TRUNCATE, 00660);
|
|
if (!outFile) {
|
|
PR_fprintf(PR_STDERR,
|
|
"%s: unable to open \"%s\" for writing (%ld, %ld).\n",
|
|
progName, certutil.options[opt_OutputFile].arg,
|
|
PR_GetError(), PR_GetOSError());
|
|
return 255;
|
|
}
|
|
}
|
|
|
|
name = SECU_GetOptionArg(&certutil, opt_Nickname);
|
|
email = SECU_GetOptionArg(&certutil, opt_Emailaddress);
|
|
|
|
PK11_SetPasswordFunc(SECU_GetModulePassword);
|
|
|
|
if (PR_TRUE == initialize) {
|
|
/* Initialize NSPR and NSS. */
|
|
PR_Init(PR_SYSTEM_THREAD, PR_PRIORITY_NORMAL, 1);
|
|
if (!certutil.commands[cmd_UpgradeMerge].activated) {
|
|
rv = NSS_Initialize(SECU_ConfigDirectory(NULL),
|
|
certPrefix, certPrefix,
|
|
"secmod.db", readOnly ? NSS_INIT_READONLY: 0);
|
|
} else {
|
|
rv = NSS_InitWithMerge(SECU_ConfigDirectory(NULL),
|
|
certPrefix, certPrefix, "secmod.db",
|
|
sourceDir, srcCertPrefix, srcCertPrefix,
|
|
upgradeID, upgradeTokenName,
|
|
readOnly ? NSS_INIT_READONLY: 0);
|
|
}
|
|
if (rv != SECSuccess) {
|
|
SECU_PrintPRandOSError(progName);
|
|
rv = SECFailure;
|
|
goto shutdown;
|
|
}
|
|
initialized = PR_TRUE;
|
|
SECU_RegisterDynamicOids();
|
|
}
|
|
certHandle = CERT_GetDefaultCertDB();
|
|
|
|
if (certutil.commands[cmd_Version].activated) {
|
|
printf("Certificate database content version: command not implemented.\n");
|
|
}
|
|
|
|
if (PL_strcmp(slotname, "internal") == 0)
|
|
slot = PK11_GetInternalKeySlot();
|
|
else if (slotname != NULL)
|
|
slot = PK11_FindSlotByName(slotname);
|
|
|
|
if ( !slot && (certutil.commands[cmd_NewDBs].activated ||
|
|
certutil.commands[cmd_ModifyCertTrust].activated ||
|
|
certutil.commands[cmd_ChangePassword].activated ||
|
|
certutil.commands[cmd_TokenReset].activated ||
|
|
certutil.commands[cmd_CreateAndAddCert].activated ||
|
|
certutil.commands[cmd_AddCert].activated ||
|
|
certutil.commands[cmd_Merge].activated ||
|
|
certutil.commands[cmd_UpgradeMerge].activated ||
|
|
certutil.commands[cmd_AddEmailCert].activated)) {
|
|
|
|
SECU_PrintError(progName, "could not find the slot %s",slotname);
|
|
rv = SECFailure;
|
|
goto shutdown;
|
|
}
|
|
|
|
/* If creating new database, initialize the password. */
|
|
if (certutil.commands[cmd_NewDBs].activated) {
|
|
if(certutil.options[opt_EmptyPassword].activated && (PK11_NeedUserInit(slot)))
|
|
PK11_InitPin(slot, (char*)NULL, "");
|
|
else
|
|
SECU_ChangePW2(slot, 0, 0, certutil.options[opt_PasswordFile].arg,
|
|
certutil.options[opt_NewPasswordFile].arg);
|
|
}
|
|
|
|
/* walk through the upgrade merge if necessary.
|
|
* This option is more to test what some applications will want to do
|
|
* to do an automatic upgrade. The --merge command is more useful for
|
|
* the general case where 2 database need to be merged together.
|
|
*/
|
|
if (certutil.commands[cmd_UpgradeMerge].activated) {
|
|
if (*upgradeTokenName == 0) {
|
|
upgradeTokenName = upgradeID;
|
|
}
|
|
if (!PK11_IsInternal(slot)) {
|
|
fprintf(stderr, "Only internal DB's can be upgraded\n");
|
|
rv = SECSuccess;
|
|
goto shutdown;
|
|
}
|
|
if (!PK11_IsRemovable(slot)) {
|
|
printf("database already upgraded.\n");
|
|
rv = SECSuccess;
|
|
goto shutdown;
|
|
}
|
|
if (!PK11_NeedLogin(slot)) {
|
|
printf("upgrade complete!\n");
|
|
rv = SECSuccess;
|
|
goto shutdown;
|
|
}
|
|
/* authenticate to the old DB if necessary */
|
|
if (PORT_Strcmp(PK11_GetTokenName(slot), upgradeTokenName) == 0) {
|
|
/* if we need a password, supply it. This will be the password
|
|
* for the old database */
|
|
rv = PK11_Authenticate(slot, PR_FALSE, &pwdata2);
|
|
if (rv != SECSuccess) {
|
|
SECU_PrintError(progName, "Could not get password for %s",
|
|
upgradeTokenName);
|
|
goto shutdown;
|
|
}
|
|
/*
|
|
* if we succeeded above, but still aren't logged in, that means
|
|
* we just supplied the password for the old database. We may
|
|
* need the password for the new database. NSS will automatically
|
|
* change the token names at this point
|
|
*/
|
|
if (PK11_IsLoggedIn(slot, &pwdata)) {
|
|
printf("upgrade complete!\n");
|
|
rv = SECSuccess;
|
|
goto shutdown;
|
|
}
|
|
}
|
|
|
|
/* call PK11_IsPresent to update our cached token information */
|
|
if (!PK11_IsPresent(slot)) {
|
|
/* this shouldn't happen. We call isPresent to force a token
|
|
* info update */
|
|
fprintf(stderr, "upgrade/merge internal error\n");
|
|
rv = SECFailure;
|
|
goto shutdown;
|
|
}
|
|
|
|
/* the token is now set to the state of the source database,
|
|
* if we need a password for it, PK11_Authenticate will
|
|
* automatically prompt us */
|
|
rv = PK11_Authenticate(slot, PR_FALSE, &pwdata);
|
|
if (rv == SECSuccess) {
|
|
printf("upgrade complete!\n");
|
|
} else {
|
|
SECU_PrintError(progName, "Could not get password for %s",
|
|
PK11_GetTokenName(slot));
|
|
}
|
|
goto shutdown;
|
|
}
|
|
|
|
/*
|
|
* merge 2 databases.
|
|
*/
|
|
if (certutil.commands[cmd_Merge].activated) {
|
|
PK11SlotInfo *sourceSlot = NULL;
|
|
PK11MergeLog *log;
|
|
char *modspec = PR_smprintf(
|
|
"configDir='%s' certPrefix='%s' tokenDescription='%s'",
|
|
sourceDir, srcCertPrefix,
|
|
*upgradeTokenName ? upgradeTokenName : "Source Database");
|
|
|
|
if (!modspec) {
|
|
rv = SECFailure;
|
|
goto shutdown;
|
|
}
|
|
|
|
sourceSlot = SECMOD_OpenUserDB(modspec);
|
|
PR_smprintf_free(modspec);
|
|
if (!sourceSlot) {
|
|
SECU_PrintError(progName, "couldn't open source database");
|
|
rv = SECFailure;
|
|
goto shutdown;
|
|
}
|
|
|
|
rv = PK11_Authenticate(slot, PR_FALSE, &pwdata);
|
|
if (rv != SECSuccess) {
|
|
SECU_PrintError(progName, "Couldn't get password for %s",
|
|
PK11_GetTokenName(slot));
|
|
goto merge_fail;
|
|
}
|
|
|
|
rv = PK11_Authenticate(sourceSlot, PR_FALSE, &pwdata2);
|
|
if (rv != SECSuccess) {
|
|
SECU_PrintError(progName, "Couldn't get password for %s",
|
|
PK11_GetTokenName(sourceSlot));
|
|
goto merge_fail;
|
|
}
|
|
|
|
log = PK11_CreateMergeLog();
|
|
if (!log) {
|
|
rv = SECFailure;
|
|
SECU_PrintError(progName, "couldn't create error log");
|
|
goto merge_fail;
|
|
}
|
|
|
|
rv = PK11_MergeTokens(slot, sourceSlot, log, &pwdata, &pwdata2);
|
|
if (rv != SECSuccess) {
|
|
DumpMergeLog(progName, log);
|
|
}
|
|
PK11_DestroyMergeLog(log);
|
|
|
|
merge_fail:
|
|
SECMOD_CloseUserDB(sourceSlot);
|
|
PK11_FreeSlot(sourceSlot);
|
|
goto shutdown;
|
|
}
|
|
|
|
/* The following 8 options are mutually exclusive with all others. */
|
|
|
|
/* List certs (-L) */
|
|
if (certutil.commands[cmd_ListCerts].activated) {
|
|
if (certutil.options[opt_DumpExtensionValue].activated) {
|
|
const char *oid_str;
|
|
SECItem oid_item;
|
|
SECStatus srv;
|
|
oid_item.data = NULL;
|
|
oid_item.len = 0;
|
|
oid_str = certutil.options[opt_DumpExtensionValue].arg;
|
|
srv = GetOidFromString(NULL, &oid_item, oid_str, strlen(oid_str));
|
|
if (srv != SECSuccess) {
|
|
SECU_PrintError(progName, "malformed extension OID %s",
|
|
oid_str);
|
|
goto shutdown;
|
|
}
|
|
rv = ListCerts(certHandle, name, email, slot,
|
|
PR_TRUE /*binary*/, PR_FALSE /*ascii*/,
|
|
&oid_item,
|
|
outFile, &pwdata);
|
|
} else {
|
|
rv = ListCerts(certHandle, name, email, slot,
|
|
certutil.options[opt_BinaryDER].activated,
|
|
certutil.options[opt_ASCIIForIO].activated,
|
|
NULL, outFile, &pwdata);
|
|
}
|
|
goto shutdown;
|
|
}
|
|
if (certutil.commands[cmd_DumpChain].activated) {
|
|
rv = DumpChain(certHandle, name,
|
|
certutil.options[opt_ASCIIForIO].activated);
|
|
goto shutdown;
|
|
}
|
|
/* XXX needs work */
|
|
/* List keys (-K) */
|
|
if (certutil.commands[cmd_ListKeys].activated) {
|
|
rv = ListKeys(slot, name, 0 /*keyindex*/, keytype, PR_FALSE /*dopriv*/,
|
|
&pwdata);
|
|
goto shutdown;
|
|
}
|
|
/* List modules (-U) */
|
|
if (certutil.commands[cmd_ListModules].activated) {
|
|
rv = ListModules();
|
|
goto shutdown;
|
|
}
|
|
/* Delete cert (-D) */
|
|
if (certutil.commands[cmd_DeleteCert].activated) {
|
|
rv = DeleteCert(certHandle, name);
|
|
goto shutdown;
|
|
}
|
|
/* Delete key (-F) */
|
|
if (certutil.commands[cmd_DeleteKey].activated) {
|
|
rv = DeleteKey(name, &pwdata);
|
|
goto shutdown;
|
|
}
|
|
/* Modify trust attribute for cert (-M) */
|
|
if (certutil.commands[cmd_ModifyCertTrust].activated) {
|
|
rv = ChangeTrustAttributes(certHandle, slot, name,
|
|
certutil.options[opt_Trust].arg, &pwdata);
|
|
goto shutdown;
|
|
}
|
|
/* Change key db password (-W) (future - change pw to slot?) */
|
|
if (certutil.commands[cmd_ChangePassword].activated) {
|
|
rv = SECU_ChangePW2(slot, 0, 0, certutil.options[opt_PasswordFile].arg,
|
|
certutil.options[opt_NewPasswordFile].arg);
|
|
goto shutdown;
|
|
}
|
|
/* Reset the a token */
|
|
if (certutil.commands[cmd_TokenReset].activated) {
|
|
char *sso_pass = "";
|
|
|
|
if (certutil.options[opt_SSOPass].activated) {
|
|
sso_pass = certutil.options[opt_SSOPass].arg;
|
|
}
|
|
rv = PK11_ResetToken(slot,sso_pass);
|
|
|
|
goto shutdown;
|
|
}
|
|
/* Check cert validity against current time (-V) */
|
|
if (certutil.commands[cmd_CheckCertValidity].activated) {
|
|
/* XXX temporary hack for fips - must log in to get priv key */
|
|
if (certutil.options[opt_VerifySig].activated) {
|
|
if (slot && PK11_NeedLogin(slot)) {
|
|
SECStatus newrv = PK11_Authenticate(slot, PR_TRUE, &pwdata);
|
|
if (newrv != SECSuccess) {
|
|
SECU_PrintError(progName, "could not authenticate to token %s.",
|
|
PK11_GetTokenName(slot));
|
|
goto shutdown;
|
|
}
|
|
}
|
|
}
|
|
rv = ValidateCert(certHandle, name,
|
|
certutil.options[opt_ValidityTime].arg,
|
|
certutil.options[opt_Usage].arg,
|
|
certutil.options[opt_VerifySig].activated,
|
|
certutil.options[opt_DetailedInfo].activated,
|
|
certutil.options[opt_ASCIIForIO].activated,
|
|
&pwdata);
|
|
if (rv != SECSuccess && PR_GetError() == SEC_ERROR_INVALID_ARGS)
|
|
SECU_PrintError(progName, "validation failed");
|
|
goto shutdown;
|
|
}
|
|
|
|
/*
|
|
* Key generation
|
|
*/
|
|
|
|
/* These commands may require keygen. */
|
|
if (certutil.commands[cmd_CertReq].activated ||
|
|
certutil.commands[cmd_CreateAndAddCert].activated ||
|
|
certutil.commands[cmd_GenKeyPair].activated) {
|
|
if (keysource) {
|
|
CERTCertificate *keycert;
|
|
keycert = CERT_FindCertByNicknameOrEmailAddr(certHandle, keysource);
|
|
if (!keycert) {
|
|
keycert = PK11_FindCertFromNickname(keysource, NULL);
|
|
if (!keycert) {
|
|
SECU_PrintError(progName,
|
|
"%s is neither a key-type nor a nickname", keysource);
|
|
return SECFailure;
|
|
}
|
|
}
|
|
privkey = PK11_FindKeyByDERCert(slot, keycert, &pwdata);
|
|
if (privkey)
|
|
pubkey = CERT_ExtractPublicKey(keycert);
|
|
if (!pubkey) {
|
|
SECU_PrintError(progName,
|
|
"Could not get keys from cert %s", keysource);
|
|
rv = SECFailure;
|
|
CERT_DestroyCertificate(keycert);
|
|
goto shutdown;
|
|
}
|
|
keytype = privkey->keyType;
|
|
/* On CertReq for renewal if no subject has been
|
|
* specified obtain it from the certificate.
|
|
*/
|
|
if (certutil.commands[cmd_CertReq].activated && !subject) {
|
|
subject = CERT_AsciiToName(keycert->subjectName);
|
|
if (!subject) {
|
|
SECU_PrintError(progName,
|
|
"Could not get subject from certificate %s", keysource);
|
|
CERT_DestroyCertificate(keycert);
|
|
rv = SECFailure;
|
|
goto shutdown;
|
|
}
|
|
}
|
|
CERT_DestroyCertificate(keycert);
|
|
} else {
|
|
privkey =
|
|
CERTUTIL_GeneratePrivateKey(keytype, slot, keysize,
|
|
publicExponent,
|
|
certutil.options[opt_NoiseFile].arg,
|
|
&pubkey,
|
|
certutil.options[opt_PQGFile].arg,
|
|
keyAttrFlags,
|
|
keyOpFlagsOn,
|
|
keyOpFlagsOff,
|
|
&pwdata);
|
|
if (privkey == NULL) {
|
|
SECU_PrintError(progName, "unable to generate key(s)\n");
|
|
rv = SECFailure;
|
|
goto shutdown;
|
|
}
|
|
}
|
|
privkey->wincx = &pwdata;
|
|
PORT_Assert(pubkey != NULL);
|
|
|
|
/* If all that was needed was keygen, exit. */
|
|
if (certutil.commands[cmd_GenKeyPair].activated) {
|
|
rv = SECSuccess;
|
|
goto shutdown;
|
|
}
|
|
}
|
|
|
|
/* If we need a list of extensions convert the flags into list format */
|
|
if (certutil.commands[cmd_CertReq].activated ||
|
|
certutil.commands[cmd_CreateAndAddCert].activated ||
|
|
certutil.commands[cmd_CreateNewCert].activated) {
|
|
certutil_extns[ext_keyUsage].activated =
|
|
certutil.options[opt_AddCmdKeyUsageExt].activated;
|
|
if (!certutil_extns[ext_keyUsage].activated) {
|
|
certutil_extns[ext_keyUsage].activated =
|
|
certutil.options[opt_AddKeyUsageExt].activated;
|
|
} else {
|
|
certutil_extns[ext_keyUsage].arg =
|
|
certutil.options[opt_AddCmdKeyUsageExt].arg;
|
|
}
|
|
certutil_extns[ext_basicConstraint].activated =
|
|
certutil.options[opt_AddBasicConstraintExt].activated;
|
|
certutil_extns[ext_nameConstraints].activated =
|
|
certutil.options[opt_AddNameConstraintsExt].activated;
|
|
certutil_extns[ext_authorityKeyID].activated =
|
|
certutil.options[opt_AddAuthorityKeyIDExt].activated;
|
|
certutil_extns[ext_subjectKeyID].activated =
|
|
certutil.options[opt_AddSubjectKeyIDExt].activated;
|
|
certutil_extns[ext_CRLDistPts].activated =
|
|
certutil.options[opt_AddCRLDistPtsExt].activated;
|
|
certutil_extns[ext_NSCertType].activated =
|
|
certutil.options[opt_AddCmdNSCertTypeExt].activated;
|
|
if (!certutil_extns[ext_NSCertType].activated) {
|
|
certutil_extns[ext_NSCertType].activated =
|
|
certutil.options[opt_AddNSCertTypeExt].activated;
|
|
} else {
|
|
certutil_extns[ext_NSCertType].arg =
|
|
certutil.options[opt_AddCmdNSCertTypeExt].arg;
|
|
}
|
|
|
|
certutil_extns[ext_extKeyUsage].activated =
|
|
certutil.options[opt_AddCmdExtKeyUsageExt].activated;
|
|
if (!certutil_extns[ext_extKeyUsage].activated) {
|
|
certutil_extns[ext_extKeyUsage].activated =
|
|
certutil.options[opt_AddExtKeyUsageExt].activated;
|
|
} else {
|
|
certutil_extns[ext_extKeyUsage].arg =
|
|
certutil.options[opt_AddCmdExtKeyUsageExt].arg;
|
|
}
|
|
certutil_extns[ext_subjectAltName].activated =
|
|
certutil.options[opt_AddSubjectAltNameExt].activated;
|
|
if (certutil_extns[ext_subjectAltName].activated) {
|
|
certutil_extns[ext_subjectAltName].arg =
|
|
certutil.options[opt_AddSubjectAltNameExt].arg;
|
|
}
|
|
|
|
certutil_extns[ext_authInfoAcc].activated =
|
|
certutil.options[opt_AddAuthInfoAccExt].activated;
|
|
certutil_extns[ext_subjInfoAcc].activated =
|
|
certutil.options[opt_AddSubjInfoAccExt].activated;
|
|
certutil_extns[ext_certPolicies].activated =
|
|
certutil.options[opt_AddCertPoliciesExt].activated;
|
|
certutil_extns[ext_policyMappings].activated =
|
|
certutil.options[opt_AddPolicyMapExt].activated;
|
|
certutil_extns[ext_policyConstr].activated =
|
|
certutil.options[opt_AddPolicyConstrExt].activated;
|
|
certutil_extns[ext_inhibitAnyPolicy].activated =
|
|
certutil.options[opt_AddInhibAnyExt].activated;
|
|
}
|
|
|
|
/* -A -C or -E Read inFile */
|
|
if (certutil.commands[cmd_CreateNewCert].activated ||
|
|
certutil.commands[cmd_AddCert].activated ||
|
|
certutil.commands[cmd_AddEmailCert].activated) {
|
|
PRBool isCreate = certutil.commands[cmd_CreateNewCert].activated;
|
|
rv = SECU_ReadDERFromFile(isCreate ? &certReqDER : &certDER, inFile,
|
|
certutil.options[opt_ASCIIForIO].activated,
|
|
PR_TRUE);
|
|
if (rv)
|
|
goto shutdown;
|
|
}
|
|
|
|
/*
|
|
* Certificate request
|
|
*/
|
|
|
|
/* Make a cert request (-R). */
|
|
if (certutil.commands[cmd_CertReq].activated) {
|
|
rv = CertReq(privkey, pubkey, keytype, hashAlgTag, subject,
|
|
certutil.options[opt_PhoneNumber].arg,
|
|
certutil.options[opt_ASCIIForIO].activated,
|
|
certutil.options[opt_ExtendedEmailAddrs].arg,
|
|
certutil.options[opt_ExtendedDNSNames].arg,
|
|
certutil_extns,
|
|
(certutil.options[opt_GenericExtensions].activated ?
|
|
certutil.options[opt_GenericExtensions].arg : NULL),
|
|
&certReqDER);
|
|
if (rv)
|
|
goto shutdown;
|
|
privkey->wincx = &pwdata;
|
|
}
|
|
|
|
/*
|
|
* Certificate creation
|
|
*/
|
|
|
|
/* If making and adding a cert, create a cert request file first without
|
|
* any extensions, then load it with the command line extensions
|
|
* and output the cert to another file.
|
|
*/
|
|
if (certutil.commands[cmd_CreateAndAddCert].activated) {
|
|
static certutilExtnList nullextnlist = {{PR_FALSE, NULL}};
|
|
rv = CertReq(privkey, pubkey, keytype, hashAlgTag, subject,
|
|
certutil.options[opt_PhoneNumber].arg,
|
|
PR_FALSE, /* do not BASE64-encode regardless of -a option */
|
|
NULL,
|
|
NULL,
|
|
nullextnlist,
|
|
(certutil.options[opt_GenericExtensions].activated ?
|
|
certutil.options[opt_GenericExtensions].arg : NULL),
|
|
&certReqDER);
|
|
if (rv)
|
|
goto shutdown;
|
|
privkey->wincx = &pwdata;
|
|
}
|
|
|
|
/* Create a certificate (-C or -S). */
|
|
if (certutil.commands[cmd_CreateAndAddCert].activated ||
|
|
certutil.commands[cmd_CreateNewCert].activated) {
|
|
rv = CreateCert(certHandle, slot,
|
|
certutil.options[opt_IssuerName].arg,
|
|
&certReqDER, &privkey, &pwdata, hashAlgTag,
|
|
serialNumber, warpmonths, validityMonths,
|
|
certutil.options[opt_ExtendedEmailAddrs].arg,
|
|
certutil.options[opt_ExtendedDNSNames].arg,
|
|
certutil.options[opt_ASCIIForIO].activated &&
|
|
certutil.commands[cmd_CreateNewCert].activated,
|
|
certutil.options[opt_SelfSign].activated,
|
|
certutil_extns,
|
|
(certutil.options[opt_GenericExtensions].activated ?
|
|
certutil.options[opt_GenericExtensions].arg : NULL),
|
|
certVersion,
|
|
&certDER);
|
|
if (rv)
|
|
goto shutdown;
|
|
}
|
|
|
|
/*
|
|
* Adding a cert to the database (or slot)
|
|
*/
|
|
|
|
/* -A -E or -S Add the cert to the DB */
|
|
if (certutil.commands[cmd_CreateAndAddCert].activated ||
|
|
certutil.commands[cmd_AddCert].activated ||
|
|
certutil.commands[cmd_AddEmailCert].activated) {
|
|
if (strstr(certutil.options[opt_Trust].arg, "u")) {
|
|
fprintf(stderr, "Notice: Trust flag u is set automatically if the "
|
|
"private key is present.\n");
|
|
}
|
|
rv = AddCert(slot, certHandle, name,
|
|
certutil.options[opt_Trust].arg,
|
|
&certDER,
|
|
certutil.commands[cmd_AddEmailCert].activated,&pwdata);
|
|
if (rv)
|
|
goto shutdown;
|
|
}
|
|
|
|
if (certutil.commands[cmd_CertReq].activated ||
|
|
certutil.commands[cmd_CreateNewCert].activated) {
|
|
SECItem * item = certutil.commands[cmd_CertReq].activated ? &certReqDER
|
|
: &certDER;
|
|
PRInt32 written = PR_Write(outFile, item->data, item->len);
|
|
if (written < 0 || (PRUint32) written != item->len) {
|
|
rv = SECFailure;
|
|
}
|
|
}
|
|
|
|
shutdown:
|
|
if (slot) {
|
|
PK11_FreeSlot(slot);
|
|
}
|
|
if (privkey) {
|
|
SECKEY_DestroyPrivateKey(privkey);
|
|
}
|
|
if (pubkey) {
|
|
SECKEY_DestroyPublicKey(pubkey);
|
|
}
|
|
if (subject) {
|
|
CERT_DestroyName(subject);
|
|
}
|
|
if (name) {
|
|
PL_strfree(name);
|
|
}
|
|
if (inFile && inFile != PR_STDIN) {
|
|
PR_Close(inFile);
|
|
}
|
|
if (outFile && outFile != PR_STDOUT) {
|
|
PR_Close(outFile);
|
|
}
|
|
SECITEM_FreeItem(&certReqDER, PR_FALSE);
|
|
SECITEM_FreeItem(&certDER, PR_FALSE);
|
|
if (pwdata.data && pwdata.source == PW_PLAINTEXT) {
|
|
/* Allocated by a PL_strdup call in SECU_GetModulePassword. */
|
|
PL_strfree(pwdata.data);
|
|
}
|
|
|
|
/* Open the batch command file.
|
|
*
|
|
* - If -B <command line> option is specified, the contents in the
|
|
* command file will be interpreted as subsequent certutil
|
|
* commands to be executed in the current certutil process
|
|
* context after the current certutil command has been executed.
|
|
* - Each line in the command file consists of the command
|
|
* line arguments for certutil.
|
|
* - The -d <configdir> option will be ignored if specified in the
|
|
* command file.
|
|
* - Quoting with double quote characters ("...") is supported
|
|
* to allow white space in a command line argument. The
|
|
* double quote character cannot be escaped and quoting cannot
|
|
* be nested in this version.
|
|
* - each line in the batch file is limited to 512 characters
|
|
*/
|
|
|
|
if ((SECSuccess == rv) && certutil.commands[cmd_Batch].activated) {
|
|
FILE* batchFile = NULL;
|
|
char *nextcommand = NULL;
|
|
PRInt32 cmd_len = 0, buf_size = 0;
|
|
static const int increment = 512;
|
|
|
|
if (!certutil.options[opt_InputFile].activated ||
|
|
!certutil.options[opt_InputFile].arg) {
|
|
PR_fprintf(PR_STDERR,
|
|
"%s: no batch input file specified.\n",
|
|
progName);
|
|
return 255;
|
|
}
|
|
batchFile = fopen(certutil.options[opt_InputFile].arg, "r");
|
|
if (!batchFile) {
|
|
PR_fprintf(PR_STDERR,
|
|
"%s: unable to open \"%s\" for reading (%ld, %ld).\n",
|
|
progName, certutil.options[opt_InputFile].arg,
|
|
PR_GetError(), PR_GetOSError());
|
|
return 255;
|
|
}
|
|
/* read and execute command-lines in a loop */
|
|
while ( SECSuccess == rv ) {
|
|
PRBool invalid = PR_FALSE;
|
|
int newargc = 2;
|
|
char* space = NULL;
|
|
char* nextarg = NULL;
|
|
char** newargv = NULL;
|
|
char* crlf;
|
|
|
|
if (cmd_len + increment > buf_size) {
|
|
char * new_buf;
|
|
buf_size += increment;
|
|
new_buf = PORT_Realloc(nextcommand, buf_size);
|
|
if (!new_buf) {
|
|
PR_fprintf(PR_STDERR, "%s: PORT_Realloc(%ld) failed\n",
|
|
progName, buf_size);
|
|
break;
|
|
}
|
|
nextcommand = new_buf;
|
|
nextcommand[cmd_len] = '\0';
|
|
}
|
|
if (!fgets(nextcommand + cmd_len, buf_size - cmd_len, batchFile)) {
|
|
break;
|
|
}
|
|
crlf = PORT_Strrchr(nextcommand, '\n');
|
|
if (crlf) {
|
|
*crlf = '\0';
|
|
}
|
|
cmd_len = strlen(nextcommand);
|
|
if (cmd_len && nextcommand[cmd_len - 1] == '\\') {
|
|
nextcommand[--cmd_len] = '\0';
|
|
continue;
|
|
}
|
|
|
|
/* we now need to split the command into argc / argv format */
|
|
|
|
newargv = PORT_Alloc(sizeof(char*)*(newargc+1));
|
|
newargv[0] = progName;
|
|
newargv[1] = nextcommand;
|
|
nextarg = nextcommand;
|
|
while ((space = PORT_Strpbrk(nextarg, " \f\n\r\t\v")) ) {
|
|
while (isspace(*space) ) {
|
|
*space = '\0';
|
|
space ++;
|
|
}
|
|
if (*space == '\0') {
|
|
break;
|
|
} else if (*space != '\"') {
|
|
nextarg = space;
|
|
} else {
|
|
char* closingquote = strchr(space+1, '\"');
|
|
if (closingquote) {
|
|
*closingquote = '\0';
|
|
space++;
|
|
nextarg = closingquote+1;
|
|
} else {
|
|
invalid = PR_TRUE;
|
|
nextarg = space;
|
|
}
|
|
}
|
|
newargc++;
|
|
newargv = PORT_Realloc(newargv, sizeof(char*)*(newargc+1));
|
|
newargv[newargc-1] = space;
|
|
}
|
|
newargv[newargc] = NULL;
|
|
|
|
/* invoke next command */
|
|
if (PR_TRUE == invalid) {
|
|
PR_fprintf(PR_STDERR, "Missing closing quote in batch command :\n%s\nNot executed.\n",
|
|
nextcommand);
|
|
rv = SECFailure;
|
|
} else {
|
|
if (0 != certutil_main(newargc, newargv, PR_FALSE) )
|
|
rv = SECFailure;
|
|
}
|
|
PORT_Free(newargv);
|
|
cmd_len = 0;
|
|
nextcommand[0] = '\0';
|
|
}
|
|
PORT_Free(nextcommand);
|
|
fclose(batchFile);
|
|
}
|
|
|
|
if ((initialized == PR_TRUE) && NSS_Shutdown() != SECSuccess) {
|
|
exit(1);
|
|
}
|
|
if (rv == SECSuccess) {
|
|
return 0;
|
|
} else {
|
|
return 255;
|
|
}
|
|
}
|
|
|
|
int
|
|
main(int argc, char **argv)
|
|
{
|
|
int rv = certutil_main(argc, argv, PR_TRUE);
|
|
PL_ArenaFinish();
|
|
PR_Cleanup();
|
|
return rv;
|
|
}
|
|
|