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