📄 certutil.c
字号:
/* * The contents of this file are subject to the Mozilla Public * License Version 1.1 (the "License"); you may not use this file * except in compliance with the License. You may obtain a copy of * the License at http://www.mozilla.org/MPL/ * * Software distributed under the License is distributed on an "AS * IS" basis, WITHOUT WARRANTY OF ANY KIND, either express or * implied. See the License for the specific language governing * rights and limitations under the License. * * The Original Code is the Netscape security libraries. * * The Initial Developer of the Original Code is Netscape * Communications Corporation. Portions created by Netscape are * Copyright (C) 1994-2000 Netscape Communications Corporation. All * Rights Reserved. * * Contributor(s): * * Alternatively, the contents of this file may be used under the * terms of the GNU General Public License Version 2 or later (the * "GPL"), in which case the provisions of the GPL are applicable * instead of those above. If you wish to allow use of your * version of this file only under the terms of the GPL and not to * allow others to use your version of this file under the MPL, * indicate your decision by deleting the provisions above and * replace them with the notice and other provisions required by * the GPL. If you do not delete the provisions above, a recipient * may use your version of this file under either the MPL or the * GPL. *//*** certutil.c**** utility for managing certificates and the cert database***/#include <stdio.h>#include <string.h>#if defined(WIN32)#include "fcntl.h"#include "io.h"#endif#include "secutil.h"#if defined(XP_UNIX)#include <unistd.h>#endif#include "nspr.h"#include "prtypes.h"#include "prtime.h"#include "prlong.h"#include "pk11func.h"#include "secasn1.h"#include "cert.h"#include "cryptohi.h"#include "secoid.h"#include "certdb.h"#include "cdbhdl.h"/* SEC_Init is now declared in secutil.h *//* We really should convert to using NSS, but it doesn't provide all * of the functionality we need (like opening the databases writeable). */#define MIN_KEY_BITS 512#define MAX_KEY_BITS 2048#define DEFAULT_KEY_BITS 1024#define GEN_BREAK(e) rv=e; break;extern SECKEYPrivateKey *CERTUTIL_GeneratePrivateKey(KeyType keytype, PK11SlotInfo *slot, int rsasize, int publicExponent, char *noise, SECKEYPublicKey **pubkeyp, char *pqgFile, char *passFile);static char *progName;static CERTGeneralName *GetGeneralName (PRArenaPool *arena){ CERTGeneralName *namesList = NULL; CERTGeneralName *current; CERTGeneralName *tail = NULL; SECStatus rv = SECSuccess; int intValue; char buffer[512]; void *mark; PORT_Assert (arena); mark = PORT_ArenaMark (arena); do { puts ("\nSelect one of the following general name type: \n"); puts ("\t1 - instance of other name\n\t2 - rfc822Name\n\t3 - dnsName\n"); puts ("\t4 - x400Address\n\t5 - directoryName\n\t6 - ediPartyName\n"); puts ("\t7 - uniformResourceidentifier\n\t8 - ipAddress\n\t9 - registerID\n"); puts ("\tOther - omit\n\t\tChoice:"); scanf ("%d", &intValue); if (intValue >= certOtherName || intValue <= certRegisterID) { if (namesList == NULL) { namesList = current = tail = (CERTGeneralName *) PORT_ArenaAlloc (arena, sizeof (CERTGeneralName)); } else { current = (CERTGeneralName *) PORT_ArenaAlloc(arena, sizeof (CERTGeneralName)); } if (current == NULL) { GEN_BREAK (SECFailure); } } else { break; } current->type = intValue; puts ("\nEnter data:"); fflush (stdout); gets (buffer); switch (current->type) { case certURI: case certDNSName: case certRFC822Name: current->name.other.data = PORT_ArenaAlloc (arena, strlen (buffer)); if (current->name.other.data == NULL) { GEN_BREAK (SECFailure); } PORT_Memcpy (current->name.other.data, buffer, current->name.other.len = strlen(buffer)); break; case certEDIPartyName: case certIPAddress: case certOtherName: case certRegisterID: case certX400Address: { current->name.other.data = PORT_ArenaAlloc (arena, strlen (buffer) + 2); if (current->name.other.data == NULL) { GEN_BREAK (SECFailure); } PORT_Memcpy (current->name.other.data + 2, buffer, strlen (buffer)); /* This may not be accurate for all cases. For now, use this tag type */ current->name.other.data[0] = (char)(((current->type - 1) & 0x1f)| 0x80); current->name.other.data[1] = (char)strlen (buffer); current->name.other.len = strlen (buffer) + 2; break; } case certDirectoryName: { CERTName *directoryName = NULL; directoryName = CERT_AsciiToName (buffer); if (!directoryName) { fprintf(stderr, "certutil: improperly formatted name: \"%s\"\n", buffer); break; } rv = CERT_CopyName (arena, ¤t->name.directoryName, directoryName); CERT_DestroyName (directoryName); break; } } if (rv != SECSuccess) break; current->l.next = &(namesList->l); current->l.prev = &(tail->l); tail->l.next = &(current->l); tail = current; }while (1); if (rv != SECSuccess) { PORT_SetError (rv); PORT_ArenaRelease (arena, mark); namesList = NULL; } return (namesList);}static SECStatus GetString(PRArenaPool *arena, char *prompt, SECItem *value){ char buffer[251]; value->data = NULL; value->len = 0; puts (prompt); gets (buffer); if (strlen (buffer) > 0) { value->data = PORT_ArenaAlloc (arena, strlen (buffer)); if (value->data == NULL) { PORT_SetError (SEC_ERROR_NO_MEMORY); return (SECFailure); } PORT_Memcpy (value->data, buffer, value->len = strlen(buffer)); } return (SECSuccess);}static CERTCertificateRequest *GetCertRequest(PRFileDesc *inFile){ CERTCertificateRequest *certReq = NULL; CERTSignedData signedData; PRArenaPool *arena = NULL; SECItem reqDER; SECStatus rv; reqDER.data = NULL; do { arena = PORT_NewArena(DER_DEFAULT_CHUNKSIZE); if (arena == NULL) { GEN_BREAK (SEC_ERROR_NO_MEMORY); } rv = SECU_ReadDERFromFile(&reqDER, inFile, PR_FALSE); if (rv) break; certReq = (CERTCertificateRequest*) PORT_ArenaZAlloc (arena, sizeof(CERTCertificateRequest)); if (!certReq) break; certReq->arena = arena; /* Since cert request is a signed data, must decode to get the inner data */ PORT_Memset(&signedData, 0, sizeof(signedData)); rv = SEC_ASN1DecodeItem(arena, &signedData, CERT_SignedDataTemplate, &reqDER); if (rv) break; rv = SEC_ASN1DecodeItem(arena, certReq, CERT_CertificateRequestTemplate, &signedData.data); } while (0); if (rv) { PRErrorCode perr = PR_GetError(); fprintf(stderr, "%s: unable to decode DER cert request (%s)\n", progName, SECU_Strerror(perr)); } return (certReq);}static PRBool GetYesNo(char *prompt) { char buf[3]; PR_Sync(PR_STDIN); PR_Write(PR_STDOUT, prompt, strlen(prompt)+1); PR_Read(PR_STDIN, buf, sizeof(buf)); return (buf[0] == 'y' || buf[0] == 'Y') ? PR_TRUE : PR_FALSE;#if 0 char charValue; puts (prompt); scanf ("%c", &charValue); if (charValue != 'y' && charValue != 'Y') return (0); return (1);#endif}static SECStatusAddCert(PK11SlotInfo *slot, CERTCertDBHandle *handle, char *name, char *trusts, PRFileDesc *inFile, PRBool ascii, PRBool emailcert){ CERTCertTrust *trust = NULL; CERTCertificate *cert = NULL, *tempCert = NULL; SECItem certDER; SECStatus rv; certDER.data = NULL; do { /* Read in the entire file specified with the -i argument */ rv = SECU_ReadDERFromFile(&certDER, inFile, ascii); if (rv != SECSuccess) { SECU_PrintError(progName, "unable to read input file"); break; } /* Read in an ASCII cert and return a CERTCertificate */ cert = CERT_DecodeCertFromPackage((char *)certDER.data, certDER.len); if (!cert) { SECU_PrintError(progName, "could not obtain certificate from file"); GEN_BREAK(SECFailure); } /* Create a cert trust to pass to SEC_AddPermCertificate */ trust = (CERTCertTrust *)PORT_ZAlloc(sizeof(CERTCertTrust)); if (!trust) { SECU_PrintError(progName, "unable to allocate cert trust"); GEN_BREAK(SECFailure); } rv = CERT_DecodeTrustString(trust, trusts); if (rv) { SECU_PrintError(progName, "unable to decode trust string"); GEN_BREAK(SECFailure); } /* CERT_ImportCert only collects certificates and returns the * first certficate. It does not insert these certificates into * the dbase. For now, just call CERT_NewTempCertificate. * This will result in decoding the der twice. This have to * be handle properly. */ tempCert = CERT_NewTempCertificate(handle, &cert->derCert, NULL, PR_FALSE, PR_TRUE); if (!PK11_IsInternal(slot)) { tempCert->trust = trust; rv = PK11_ImportCertForKeyToSlot(slot, tempCert, name, PR_FALSE, NULL); } if (tempCert == NULL) { SECU_PrintError(progName,"unable to add cert to the temp database"); GEN_BREAK(SECFailure); } rv = CERT_AddTempCertToPerm(tempCert, name, trust); if (rv) { SECU_PrintError(progName, "could not add certificate to database"); GEN_BREAK(SECFailure); } if ( emailcert ) CERT_SaveSMimeProfile(tempCert, NULL, NULL); } while (0); CERT_DestroyCertificate (tempCert); CERT_DestroyCertificate (cert); PORT_Free(trust); PORT_Free(certDER.data); return rv;}static SECStatusCertReq(SECKEYPrivateKey *privk, SECKEYPublicKey *pubk, KeyType keyType, CERTName *subject, char *phone, int ascii, PRFileDesc *outFile){ CERTSubjectPublicKeyInfo *spki; CERTCertificateRequest *cr; SECItem *encoding; SECItem result; SECStatus rv; PRArenaPool *arena; PRInt32 numBytes; /* Create info about public key */ spki = SECKEY_CreateSubjectPublicKeyInfo(pubk); if (!spki) { SECU_PrintError(progName, "unable to create subject public key"); return SECFailure; } /* Generate certificate request */ cr = CERT_CreateCertificateRequest(subject, spki, 0); if (!cr) { SECU_PrintError(progName, "unable to make certificate request"); return SECFailure; } arena = PORT_NewArena(DER_DEFAULT_CHUNKSIZE); if ( !arena ) { SECU_PrintError(progName, "out of memory"); return SECFailure; } /* Der encode the request */ encoding = SEC_ASN1EncodeItem(arena, NULL, cr, CERT_CertificateRequestTemplate); if (encoding == NULL) { SECU_PrintError(progName, "der encoding of request failed"); return SECFailure; } /* Sign the request */ switch (keyType) { case rsaKey: rv = SEC_DerSignData(arena, &result, encoding->data, encoding->len, privk, SEC_OID_PKCS1_MD5_WITH_RSA_ENCRYPTION); break; case dsaKey: rv = SEC_DerSignData(arena, &result, encoding->data, encoding->len, privk, SEC_OID_ANSIX9_DSA_SIGNATURE_WITH_SHA1_DIGEST); break; default: SECU_PrintError(progName, "Must use rsa or dsa key type"); return SECFailure; } if (rv) { SECU_PrintError(progName, "signing of data failed"); return SECFailure; } /* Encode request in specified format */ if (ascii) { char *obuf; char *name, *email, *org, *state, *country; SECItem *it; int total; it = &result; obuf = BTOA_ConvertItemToAscii(it); total = PL_strlen(obuf); name = CERT_GetCommonName(subject); if (!name) { fprintf(stderr, "You must specify a common name\n"); return SECFailure; } if (!phone) phone = strdup("(not specified)"); email = CERT_GetCertEmailAddress(subject); if (!email) email = strdup("(not specified)"); org = CERT_GetOrgName(subject); if (!org) org = strdup("(not specified)"); state = CERT_GetStateName(subject); if (!state) state = strdup("(not specified)"); country = CERT_GetCountryName(subject); if (!country) country = strdup("(not specified)"); PR_fprintf(outFile, "\nCertificate request generated by Netscape certutil\n"); PR_fprintf(outFile, "Phone: %s\n\n", phone); PR_fprintf(outFile, "Common Name: %s\n", name); PR_fprintf(outFile, "Email: %s\n", email); PR_fprintf(outFile, "Organization: %s\n", org);
⌨️ 快捷键说明
复制代码
Ctrl + C
搜索代码
Ctrl + F
全屏模式
F11
切换主题
Ctrl + Shift + D
显示快捷键
?
增大字号
Ctrl + =
减小字号
Ctrl + -