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: #include "signtool.h" michael@0: michael@0: #include "secoid.h" michael@0: #include "cryptohi.h" michael@0: #include "certdb.h" michael@0: michael@0: static char *GetSubjectFromUser(unsigned long serial); michael@0: static CERTCertificate*GenerateSelfSignedObjectSigningCert(char *nickname, michael@0: CERTCertDBHandle *db, char *subject, unsigned long serial, int keysize, michael@0: char *token); michael@0: static SECStatus ChangeTrustAttributes(CERTCertDBHandle *db, michael@0: CERTCertificate *cert, char *trusts); michael@0: static SECStatus set_cert_type(CERTCertificate *cert, unsigned int type); michael@0: static SECItem *sign_cert(CERTCertificate *cert, SECKEYPrivateKey *privk); michael@0: static CERTCertificate*install_cert(CERTCertDBHandle *db, SECItem *derCert, michael@0: char *nickname); michael@0: static SECStatus GenerateKeyPair(PK11SlotInfo *slot, SECKEYPublicKey **pubk, michael@0: SECKEYPrivateKey **privk, int keysize); michael@0: static CERTCertificateRequest*make_cert_request(char *subject, michael@0: SECKEYPublicKey *pubk); michael@0: static CERTCertificate *make_cert(CERTCertificateRequest *req, michael@0: unsigned long serial, CERTName *ca_subject); michael@0: static void output_ca_cert (CERTCertificate *cert, CERTCertDBHandle *db); michael@0: michael@0: michael@0: /*********************************************************************** michael@0: * michael@0: * G e n e r a t e C e r t michael@0: * michael@0: * Runs the whole process of creating a new cert, getting info from the michael@0: * user, etc. michael@0: */ michael@0: int michael@0: GenerateCert(char *nickname, int keysize, char *token) michael@0: { michael@0: CERTCertDBHandle * db; michael@0: CERTCertificate * cert; michael@0: char *subject; michael@0: unsigned long serial; michael@0: char stdinbuf[160]; michael@0: michael@0: /* Print warning about having the browser open */ michael@0: PR_fprintf(PR_STDOUT /*always go to console*/, michael@0: "\nWARNING: Performing this operation while the browser is running could cause" michael@0: "\ncorruption of your security databases. If the browser is currently running," michael@0: "\nyou should exit the browser before continuing this operation. Enter " michael@0: "\n\"y\" to continue, or anything else to abort: "); michael@0: pr_fgets(stdinbuf, 160, PR_STDIN); michael@0: PR_fprintf(PR_STDOUT, "\n"); michael@0: if (tolower(stdinbuf[0]) != 'y') { michael@0: PR_fprintf(errorFD, "Operation aborted at user's request.\n"); michael@0: errorCount++; michael@0: return - 1; michael@0: } michael@0: michael@0: db = CERT_GetDefaultCertDB(); michael@0: if (!db) { michael@0: FatalError("Unable to open certificate database"); michael@0: } michael@0: michael@0: if (PK11_FindCertFromNickname(nickname, &pwdata)) { michael@0: PR_fprintf(errorFD, michael@0: "ERROR: Certificate with nickname \"%s\" already exists in database. You\n" michael@0: "must choose a different nickname.\n", nickname); michael@0: errorCount++; michael@0: exit(ERRX); michael@0: } michael@0: michael@0: LL_L2UI(serial, PR_Now()); michael@0: michael@0: subject = GetSubjectFromUser(serial); michael@0: michael@0: cert = GenerateSelfSignedObjectSigningCert(nickname, db, subject, michael@0: serial, keysize, token); michael@0: michael@0: if (cert) { michael@0: output_ca_cert(cert, db); michael@0: CERT_DestroyCertificate(cert); michael@0: } michael@0: michael@0: PORT_Free(subject); michael@0: return 0; michael@0: } michael@0: michael@0: michael@0: #undef VERBOSE_PROMPTS michael@0: michael@0: /*********************************************************************8 michael@0: * G e t S u b j e c t F r o m U s e r michael@0: * michael@0: * Construct the subject information line for a certificate by querying michael@0: * the user on stdin. michael@0: */ michael@0: static char * michael@0: GetSubjectFromUser(unsigned long serial) michael@0: { michael@0: char buf[STDIN_BUF_SIZE]; michael@0: char common_name_buf[STDIN_BUF_SIZE]; michael@0: char *common_name, *state, *orgunit, *country, *org, *locality; michael@0: char *email, *uid; michael@0: char *subject; michael@0: char *cp; michael@0: int subjectlen = 0; michael@0: michael@0: common_name = state = orgunit = country = org = locality = email = michael@0: uid = subject = NULL; michael@0: michael@0: /* Get subject information */ michael@0: PR_fprintf(PR_STDOUT, michael@0: "\nEnter certificate information. All fields are optional. Acceptable\n" michael@0: "characters are numbers, letters, spaces, and apostrophes.\n"); michael@0: michael@0: #ifdef VERBOSE_PROMPTS michael@0: PR_fprintf(PR_STDOUT, "\nCOMMON NAME\n" michael@0: "Enter the full name you want to give your certificate. (Example: Test-Only\n" michael@0: "Object Signing Certificate)\n" michael@0: "-->"); michael@0: #else michael@0: PR_fprintf(PR_STDOUT, "certificate common name: "); michael@0: #endif michael@0: fgets(buf, STDIN_BUF_SIZE, stdin); michael@0: cp = chop(buf); michael@0: if (*cp == '\0') { michael@0: sprintf(common_name_buf, "%s (%lu)", DEFAULT_COMMON_NAME, michael@0: serial); michael@0: cp = common_name_buf; michael@0: } michael@0: common_name = PORT_ZAlloc(strlen(cp) + 6); michael@0: if (!common_name) { michael@0: out_of_memory(); michael@0: } michael@0: sprintf(common_name, "CN=%s, ", cp); michael@0: subjectlen += strlen(common_name); michael@0: michael@0: #ifdef VERBOSE_PROMPTS michael@0: PR_fprintf(PR_STDOUT, "\nORGANIZATION NAME\n" michael@0: "Enter the name of your organization. For example, this could be the name\n" michael@0: "of your company.\n" michael@0: "-->"); michael@0: #else michael@0: PR_fprintf(PR_STDOUT, "organization: "); michael@0: #endif michael@0: fgets(buf, STDIN_BUF_SIZE, stdin); michael@0: cp = chop(buf); michael@0: if (*cp != '\0') { michael@0: org = PORT_ZAlloc(strlen(cp) + 5); michael@0: if (!org) { michael@0: out_of_memory(); michael@0: } michael@0: sprintf(org, "O=%s, ", cp); michael@0: subjectlen += strlen(org); michael@0: } michael@0: michael@0: #ifdef VERBOSE_PROMPTS michael@0: PR_fprintf(PR_STDOUT, "\nORGANIZATION UNIT\n" michael@0: "Enter the name of your organization unit. For example, this could be the\n" michael@0: "name of your department.\n" michael@0: "-->"); michael@0: #else michael@0: PR_fprintf(PR_STDOUT, "organization unit: "); michael@0: #endif michael@0: fgets(buf, STDIN_BUF_SIZE, stdin); michael@0: cp = chop(buf); michael@0: if (*cp != '\0') { michael@0: orgunit = PORT_ZAlloc(strlen(cp) + 6); michael@0: if (!orgunit) { michael@0: out_of_memory(); michael@0: } michael@0: sprintf(orgunit, "OU=%s, ", cp); michael@0: subjectlen += strlen(orgunit); michael@0: } michael@0: michael@0: #ifdef VERBOSE_PROMPTS michael@0: PR_fprintf(PR_STDOUT, "\nSTATE\n" michael@0: "Enter the name of your state or province.\n" michael@0: "-->"); michael@0: #else michael@0: PR_fprintf(PR_STDOUT, "state or province: "); michael@0: #endif michael@0: fgets(buf, STDIN_BUF_SIZE, stdin); michael@0: cp = chop(buf); michael@0: if (*cp != '\0') { michael@0: state = PORT_ZAlloc(strlen(cp) + 6); michael@0: if (!state) { michael@0: out_of_memory(); michael@0: } michael@0: sprintf(state, "ST=%s, ", cp); michael@0: subjectlen += strlen(state); michael@0: } michael@0: michael@0: #ifdef VERBOSE_PROMPTS michael@0: PR_fprintf(PR_STDOUT, "\nCOUNTRY\n" michael@0: "Enter the 2-character abbreviation for the name of your country.\n" michael@0: "-->"); michael@0: #else michael@0: PR_fprintf(PR_STDOUT, "country (must be exactly 2 characters): "); michael@0: #endif michael@0: fgets(buf, STDIN_BUF_SIZE, stdin); michael@0: cp = chop(cp); michael@0: if (strlen(cp) != 2) { michael@0: *cp = '\0'; /* country code must be 2 chars */ michael@0: } michael@0: if (*cp != '\0') { michael@0: country = PORT_ZAlloc(strlen(cp) + 5); michael@0: if (!country) { michael@0: out_of_memory(); michael@0: } michael@0: sprintf(country, "C=%s, ", cp); michael@0: subjectlen += strlen(country); michael@0: } michael@0: michael@0: #ifdef VERBOSE_PROMPTS michael@0: PR_fprintf(PR_STDOUT, "\nUSERNAME\n" michael@0: "Enter your system username or UID\n" michael@0: "-->"); michael@0: #else michael@0: PR_fprintf(PR_STDOUT, "username: "); michael@0: #endif michael@0: fgets(buf, STDIN_BUF_SIZE, stdin); michael@0: cp = chop(buf); michael@0: if (*cp != '\0') { michael@0: uid = PORT_ZAlloc(strlen(cp) + 7); michael@0: if (!uid) { michael@0: out_of_memory(); michael@0: } michael@0: sprintf(uid, "UID=%s, ", cp); michael@0: subjectlen += strlen(uid); michael@0: } michael@0: michael@0: #ifdef VERBOSE_PROMPTS michael@0: PR_fprintf(PR_STDOUT, "\nEMAIL ADDRESS\n" michael@0: "Enter your email address.\n" michael@0: "-->"); michael@0: #else michael@0: PR_fprintf(PR_STDOUT, "email address: "); michael@0: #endif michael@0: fgets(buf, STDIN_BUF_SIZE, stdin); michael@0: cp = chop(buf); michael@0: if (*cp != '\0') { michael@0: email = PORT_ZAlloc(strlen(cp) + 5); michael@0: if (!email) { michael@0: out_of_memory(); michael@0: } michael@0: sprintf(email, "E=%s,", cp); michael@0: subjectlen += strlen(email); michael@0: } michael@0: michael@0: subjectlen++; michael@0: michael@0: subject = PORT_ZAlloc(subjectlen); michael@0: if (!subject) { michael@0: out_of_memory(); michael@0: } michael@0: michael@0: sprintf(subject, "%s%s%s%s%s%s%s", michael@0: common_name ? common_name : "", michael@0: org ? org : "", michael@0: orgunit ? orgunit : "", michael@0: state ? state : "", michael@0: country ? country : "", michael@0: uid ? uid : "", michael@0: email ? email : "" michael@0: ); michael@0: if ( (strlen(subject) > 1) && (subject[strlen(subject)-1] == ' ') ) { michael@0: subject[strlen(subject)-2] = '\0'; michael@0: } michael@0: michael@0: PORT_Free(common_name); michael@0: PORT_Free(org); michael@0: PORT_Free(orgunit); michael@0: PORT_Free(state); michael@0: PORT_Free(country); michael@0: PORT_Free(uid); michael@0: PORT_Free(email); michael@0: michael@0: return subject; michael@0: } michael@0: michael@0: michael@0: /************************************************************************** michael@0: * michael@0: * G e n e r a t e S e l f S i g n e d O b j e c t S i g n i n g C e r t michael@0: * *phew*^ michael@0: * michael@0: */ michael@0: static CERTCertificate* michael@0: GenerateSelfSignedObjectSigningCert(char *nickname, CERTCertDBHandle *db, michael@0: char *subject, unsigned long serial, int keysize, char *token) michael@0: { michael@0: CERTCertificate * cert, *temp_cert; michael@0: SECItem * derCert; michael@0: CERTCertificateRequest * req; michael@0: michael@0: PK11SlotInfo * slot = NULL; michael@0: SECKEYPrivateKey * privk = NULL; michael@0: SECKEYPublicKey * pubk = NULL; michael@0: michael@0: if ( token ) { michael@0: slot = PK11_FindSlotByName(token); michael@0: } else { michael@0: slot = PK11_GetInternalKeySlot(); michael@0: } michael@0: michael@0: if (slot == NULL) { michael@0: PR_fprintf(errorFD, "Can't find PKCS11 slot %s\n", michael@0: token ? token : ""); michael@0: errorCount++; michael@0: exit (ERRX); michael@0: } michael@0: michael@0: if ( GenerateKeyPair(slot, &pubk, &privk, keysize) != SECSuccess) { michael@0: FatalError("Error generating keypair."); michael@0: } michael@0: req = make_cert_request (subject, pubk); michael@0: temp_cert = make_cert (req, serial, &req->subject); michael@0: if (set_cert_type(temp_cert, michael@0: NS_CERT_TYPE_OBJECT_SIGNING | NS_CERT_TYPE_OBJECT_SIGNING_CA) michael@0: != SECSuccess) { michael@0: FatalError("Unable to set cert type"); michael@0: } michael@0: michael@0: derCert = sign_cert (temp_cert, privk); michael@0: cert = install_cert(db, derCert, nickname); michael@0: if (ChangeTrustAttributes(db, cert, ",,uC") != SECSuccess) { michael@0: FatalError("Unable to change trust on generated certificate"); michael@0: } michael@0: michael@0: /* !!! Free memory ? !!! */ michael@0: PK11_FreeSlot(slot); michael@0: SECKEY_DestroyPrivateKey(privk); michael@0: SECKEY_DestroyPublicKey(pubk); michael@0: michael@0: return cert; michael@0: } michael@0: michael@0: michael@0: /************************************************************************** michael@0: * michael@0: * C h a n g e T r u s t A t t r i b u t e s michael@0: */ michael@0: static SECStatus michael@0: ChangeTrustAttributes(CERTCertDBHandle *db, CERTCertificate *cert, char *trusts) michael@0: { michael@0: michael@0: CERTCertTrust * trust; michael@0: michael@0: if (!db || !cert || !trusts) { michael@0: PR_fprintf(errorFD, "ChangeTrustAttributes got incomplete arguments.\n"); michael@0: errorCount++; michael@0: return SECFailure; michael@0: } michael@0: michael@0: trust = (CERTCertTrust * ) PORT_ZAlloc(sizeof(CERTCertTrust)); michael@0: if (!trust) { michael@0: PR_fprintf(errorFD, "ChangeTrustAttributes unable to allocate " michael@0: "CERTCertTrust\n"); michael@0: errorCount++; michael@0: return SECFailure; michael@0: } michael@0: michael@0: if ( CERT_DecodeTrustString(trust, trusts) ) { michael@0: return SECFailure; michael@0: } michael@0: michael@0: if ( CERT_ChangeCertTrust(db, cert, trust) ) { michael@0: PR_fprintf(errorFD, "unable to modify trust attributes for cert %s\n", michael@0: cert->nickname ? cert->nickname : ""); michael@0: errorCount++; michael@0: return SECFailure; michael@0: } michael@0: michael@0: return SECSuccess; michael@0: } michael@0: michael@0: michael@0: /************************************************************************* michael@0: * michael@0: * s e t _ c e r t _ t y p e michael@0: */ michael@0: static SECStatus michael@0: set_cert_type(CERTCertificate *cert, unsigned int type) michael@0: { michael@0: void *context; michael@0: SECStatus status = SECSuccess; michael@0: SECItem certType; michael@0: char ctype; michael@0: michael@0: context = CERT_StartCertExtensions(cert); michael@0: michael@0: certType.type = siBuffer; michael@0: certType.data = (unsigned char * ) &ctype; michael@0: certType.len = 1; michael@0: ctype = (unsigned char)type; michael@0: if (CERT_EncodeAndAddBitStrExtension(context, SEC_OID_NS_CERT_EXT_CERT_TYPE, michael@0: &certType, PR_TRUE /*critical*/) != SECSuccess) { michael@0: status = SECFailure; michael@0: } michael@0: michael@0: if (CERT_FinishExtensions(context) != SECSuccess) { michael@0: status = SECFailure; michael@0: } michael@0: michael@0: return status; michael@0: } michael@0: michael@0: michael@0: /******************************************************************** michael@0: * michael@0: * s i g n _ c e r t michael@0: */ michael@0: static SECItem * michael@0: sign_cert(CERTCertificate *cert, SECKEYPrivateKey *privk) michael@0: { michael@0: SECStatus rv; michael@0: michael@0: SECItem der2; michael@0: SECItem * result2; michael@0: michael@0: void *dummy; michael@0: SECOidTag alg = SEC_OID_UNKNOWN; michael@0: michael@0: alg = SEC_GetSignatureAlgorithmOidTag(privk->keyType, SEC_OID_UNKNOWN); michael@0: if (alg == SEC_OID_UNKNOWN) { michael@0: FatalError("Unknown key type"); michael@0: } michael@0: michael@0: rv = SECOID_SetAlgorithmID (cert->arena, &cert->signature, alg, 0); michael@0: michael@0: if (rv != SECSuccess) { michael@0: PR_fprintf(errorFD, "%s: unable to set signature alg id\n", michael@0: PROGRAM_NAME); michael@0: errorCount++; michael@0: exit (ERRX); michael@0: } michael@0: michael@0: der2.len = 0; michael@0: der2.data = NULL; michael@0: michael@0: dummy = SEC_ASN1EncodeItem michael@0: (cert->arena, &der2, cert, SEC_ASN1_GET(CERT_CertificateTemplate)); michael@0: michael@0: if (rv != SECSuccess) { michael@0: PR_fprintf(errorFD, "%s: error encoding cert\n", PROGRAM_NAME); michael@0: errorCount++; michael@0: exit (ERRX); michael@0: } michael@0: michael@0: result2 = (SECItem * ) PORT_ArenaZAlloc (cert->arena, sizeof (SECItem)); michael@0: if (result2 == NULL) michael@0: out_of_memory(); michael@0: michael@0: rv = SEC_DerSignData michael@0: (cert->arena, result2, der2.data, der2.len, privk, alg); michael@0: michael@0: if (rv != SECSuccess) { michael@0: PR_fprintf(errorFD, "can't sign encoded certificate data\n"); michael@0: errorCount++; michael@0: exit (ERRX); michael@0: } else if (verbosity >= 0) { michael@0: PR_fprintf(outputFD, "certificate has been signed\n"); michael@0: } michael@0: michael@0: cert->derCert = *result2; michael@0: michael@0: return result2; michael@0: } michael@0: michael@0: michael@0: /********************************************************************* michael@0: * michael@0: * i n s t a l l _ c e r t michael@0: * michael@0: * Installs the cert in the permanent database. michael@0: */ michael@0: static CERTCertificate* michael@0: install_cert(CERTCertDBHandle *db, SECItem *derCert, char *nickname) michael@0: { michael@0: CERTCertificate * newcert; michael@0: PK11SlotInfo * newSlot; michael@0: michael@0: michael@0: newSlot = PK11_ImportDERCertForKey(derCert, nickname, &pwdata); michael@0: if ( newSlot == NULL ) { michael@0: PR_fprintf(errorFD, "Unable to install certificate\n"); michael@0: errorCount++; michael@0: exit(ERRX); michael@0: } michael@0: michael@0: newcert = PK11_FindCertFromDERCertItem(newSlot, derCert, &pwdata); michael@0: PK11_FreeSlot(newSlot); michael@0: if (newcert == NULL) { michael@0: PR_fprintf(errorFD, "%s: can't find new certificate\n", michael@0: PROGRAM_NAME); michael@0: errorCount++; michael@0: exit (ERRX); michael@0: } michael@0: michael@0: if (verbosity >= 0) { michael@0: PR_fprintf(outputFD, "certificate \"%s\" added to database\n", michael@0: nickname); michael@0: } michael@0: michael@0: return newcert; michael@0: } michael@0: michael@0: michael@0: /****************************************************************** michael@0: * michael@0: * G e n e r a t e K e y P a i r michael@0: */ michael@0: static SECStatus michael@0: GenerateKeyPair(PK11SlotInfo *slot, SECKEYPublicKey **pubk, michael@0: SECKEYPrivateKey **privk, int keysize) michael@0: { michael@0: michael@0: PK11RSAGenParams rsaParams; michael@0: michael@0: if ( keysize == -1 ) { michael@0: rsaParams.keySizeInBits = DEFAULT_RSA_KEY_SIZE; michael@0: } else { michael@0: rsaParams.keySizeInBits = keysize; michael@0: } michael@0: rsaParams.pe = 0x10001; michael@0: michael@0: if (PK11_Authenticate( slot, PR_FALSE /*loadCerts*/, &pwdata) michael@0: != SECSuccess) { michael@0: SECU_PrintError(progName, "failure authenticating to key database.\n"); michael@0: exit(ERRX); michael@0: } michael@0: michael@0: *privk = PK11_GenerateKeyPair (slot, CKM_RSA_PKCS_KEY_PAIR_GEN, &rsaParams, michael@0: michael@0: pubk, PR_TRUE /*isPerm*/, PR_TRUE /*isSensitive*/, &pwdata); michael@0: michael@0: if (*privk != NULL && *pubk != NULL) { michael@0: if (verbosity >= 0) { michael@0: PR_fprintf(outputFD, "generated public/private key pair\n"); michael@0: } michael@0: } else { michael@0: SECU_PrintError(progName, "failure generating key pair\n"); michael@0: exit (ERRX); michael@0: } michael@0: michael@0: return SECSuccess; michael@0: } michael@0: michael@0: michael@0: michael@0: /****************************************************************** michael@0: * michael@0: * m a k e _ c e r t _ r e q u e s t michael@0: */ michael@0: static CERTCertificateRequest* michael@0: make_cert_request(char *subject, SECKEYPublicKey *pubk) michael@0: { michael@0: CERTName * subj; michael@0: CERTSubjectPublicKeyInfo * spki; michael@0: michael@0: CERTCertificateRequest * req; 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: exit (ERRX); michael@0: } michael@0: michael@0: subj = CERT_AsciiToName (subject); michael@0: if (subj == NULL) { michael@0: FatalError("Invalid data in certificate description"); michael@0: } michael@0: michael@0: /* Generate certificate request */ michael@0: req = CERT_CreateCertificateRequest(subj, spki, 0); michael@0: if (!req) { michael@0: SECU_PrintError(progName, "unable to make certificate request"); michael@0: exit (ERRX); michael@0: } michael@0: michael@0: SECKEY_DestroySubjectPublicKeyInfo(spki); michael@0: CERT_DestroyName(subj); michael@0: michael@0: if (verbosity >= 0) { michael@0: PR_fprintf(outputFD, "certificate request generated\n"); michael@0: } michael@0: michael@0: return req; michael@0: } michael@0: michael@0: michael@0: /****************************************************************** michael@0: * michael@0: * m a k e _ c e r t michael@0: */ michael@0: static CERTCertificate * michael@0: make_cert(CERTCertificateRequest *req, unsigned long serial, michael@0: CERTName *ca_subject) michael@0: { michael@0: CERTCertificate * cert; michael@0: michael@0: CERTValidity * validity = NULL; michael@0: michael@0: PRTime now, after; michael@0: PRExplodedTime printableTime; michael@0: michael@0: now = PR_Now(); michael@0: PR_ExplodeTime (now, PR_GMTParameters, &printableTime); michael@0: michael@0: printableTime.tm_month += 3; michael@0: after = PR_ImplodeTime (&printableTime); michael@0: michael@0: validity = CERT_CreateValidity (now, after); michael@0: michael@0: if (validity == NULL) { michael@0: PR_fprintf(errorFD, "%s: error creating certificate validity\n", michael@0: PROGRAM_NAME); michael@0: errorCount++; michael@0: exit (ERRX); michael@0: } michael@0: michael@0: cert = CERT_CreateCertificate michael@0: (serial, ca_subject, validity, req); michael@0: michael@0: if (cert == NULL) { michael@0: /* should probably be more precise here */ michael@0: PR_fprintf(errorFD, "%s: error while generating certificate\n", michael@0: PROGRAM_NAME); michael@0: errorCount++; michael@0: exit (ERRX); michael@0: } michael@0: michael@0: return cert; michael@0: } michael@0: michael@0: michael@0: /************************************************************************* michael@0: * michael@0: * o u t p u t _ c a _ c e r t michael@0: */ michael@0: static void michael@0: output_ca_cert (CERTCertificate *cert, CERTCertDBHandle *db) michael@0: { michael@0: FILE * out; michael@0: michael@0: SECItem * encodedCertChain; michael@0: SEC_PKCS7ContentInfo * certChain; michael@0: char *filename; michael@0: michael@0: /* the raw */ michael@0: michael@0: filename = PORT_ZAlloc(strlen(DEFAULT_X509_BASENAME) + 8); michael@0: if (!filename) michael@0: out_of_memory(); michael@0: michael@0: sprintf(filename, "%s.raw", DEFAULT_X509_BASENAME); michael@0: if ((out = fopen (filename, "wb")) == NULL) { michael@0: PR_fprintf(errorFD, "%s: Can't open %s output file\n", PROGRAM_NAME, michael@0: filename); michael@0: errorCount++; michael@0: exit(ERRX); michael@0: } michael@0: michael@0: certChain = SEC_PKCS7CreateCertsOnly (cert, PR_TRUE, db); michael@0: encodedCertChain michael@0: = SEC_PKCS7EncodeItem (NULL, NULL, certChain, NULL, NULL, NULL); michael@0: SEC_PKCS7DestroyContentInfo (certChain); michael@0: michael@0: if (encodedCertChain) { michael@0: fprintf(out, "Content-type: application/x-x509-ca-cert\n\n"); michael@0: fwrite (encodedCertChain->data, 1, encodedCertChain->len, michael@0: out); michael@0: SECITEM_FreeItem(encodedCertChain, PR_TRUE); michael@0: } else { michael@0: PR_fprintf(errorFD, "%s: Can't DER encode this certificate\n", michael@0: PROGRAM_NAME); michael@0: errorCount++; michael@0: exit(ERRX); michael@0: } michael@0: michael@0: fclose (out); michael@0: michael@0: /* and the cooked */ michael@0: michael@0: sprintf(filename, "%s.cacert", DEFAULT_X509_BASENAME); michael@0: if ((out = fopen (filename, "wb")) == NULL) { michael@0: PR_fprintf(errorFD, "%s: Can't open %s output file\n", PROGRAM_NAME, michael@0: filename); michael@0: errorCount++; michael@0: return; michael@0: } michael@0: michael@0: fprintf (out, "%s\n%s\n%s\n", michael@0: NS_CERT_HEADER, michael@0: BTOA_DataToAscii (cert->derCert.data, cert->derCert.len), michael@0: NS_CERT_TRAILER); michael@0: michael@0: fclose (out); michael@0: michael@0: if (verbosity >= 0) { michael@0: PR_fprintf(outputFD, "Exported certificate to %s.raw and %s.cacert.\n", michael@0: DEFAULT_X509_BASENAME, DEFAULT_X509_BASENAME); michael@0: } michael@0: } michael@0: michael@0: