diff options
author | Daniel Baumann <daniel.baumann@progress-linux.org> | 2024-04-07 19:33:14 +0000 |
---|---|---|
committer | Daniel Baumann <daniel.baumann@progress-linux.org> | 2024-04-07 19:33:14 +0000 |
commit | 36d22d82aa202bb199967e9512281e9a53db42c9 (patch) | |
tree | 105e8c98ddea1c1e4784a60a5a6410fa416be2de /security/nss/doc/rst/legacy/nss_sample_code/enc_dec_mac_using_key_wrap_certreq_pkcs10_csr/index.rst | |
parent | Initial commit. (diff) | |
download | firefox-esr-36d22d82aa202bb199967e9512281e9a53db42c9.tar.xz firefox-esr-36d22d82aa202bb199967e9512281e9a53db42c9.zip |
Adding upstream version 115.7.0esr.upstream/115.7.0esrupstream
Signed-off-by: Daniel Baumann <daniel.baumann@progress-linux.org>
Diffstat (limited to 'security/nss/doc/rst/legacy/nss_sample_code/enc_dec_mac_using_key_wrap_certreq_pkcs10_csr/index.rst')
-rw-r--r-- | security/nss/doc/rst/legacy/nss_sample_code/enc_dec_mac_using_key_wrap_certreq_pkcs10_csr/index.rst | 2090 |
1 files changed, 2090 insertions, 0 deletions
diff --git a/security/nss/doc/rst/legacy/nss_sample_code/enc_dec_mac_using_key_wrap_certreq_pkcs10_csr/index.rst b/security/nss/doc/rst/legacy/nss_sample_code/enc_dec_mac_using_key_wrap_certreq_pkcs10_csr/index.rst new file mode 100644 index 0000000000..793555ce5a --- /dev/null +++ b/security/nss/doc/rst/legacy/nss_sample_code/enc_dec_mac_using_key_wrap_certreq_pkcs10_csr/index.rst @@ -0,0 +1,2090 @@ +.. _mozilla_projects_nss_nss_sample_code_enc_dec_mac_using_key_wrap_certreq_pkcs10_csr: + +Enc Dec MAC Using Key Wrap CertReq PKCS10 CSR +============================================= + +.. _nss_sample_code_6_encryptiondecryption_and_mac_and_output_public_as_a_pkcs_11_csr.: + +`NSS Sample Code 6: Encryption/Decryption and MAC and output Public as a PKCS 11 CSR. <#nss_sample_code_6_encryptiondecryption_and_mac_and_output_public_as_a_pkcs_11_csr.>`__ +------------------------------------------------------------------------------------------------------------------------------------------------------------------------------ + +.. container:: + + Generates encryption/mac keys and outputs public key as pkcs11 certificate signing request + + .. code:: c + + /* This Source Code Form is subject to the terms of the Mozilla Public + * License, v. 2.0. If a copy of the MPL was not distributed with this + * file, You can obtain one at https://mozilla.org/MPL/2.0/. */ + + /* NSPR Headers */ + #include <prthread.h> + #include <plgetopt.h> + #include <prerror.h> + #include <prinit.h> + #include <prlog.h> + #include <prtypes.h> + #include <plstr.h> + + /* NSS headers */ + #include <keyhi.h> + #include <pk11priv.h> + + /* our samples utilities */ + #include "util.h" + + /* Constants */ + #define BLOCKSIZE 32 + #define MODBLOCKSIZE 128 + #define DEFAULT_KEY_BITS 1024 + + /* Header file Constants */ + #define ENCKEY_HEADER "-----BEGIN WRAPPED ENCKEY-----" + #define ENCKEY_TRAILER "-----END WRAPPED ENCKEY-----" + #define MACKEY_HEADER "-----BEGIN WRAPPED MACKEY-----" + #define MACKEY_TRAILER "-----END WRAPPED MACKEY-----" + #define IV_HEADER "-----BEGIN IV-----" + #define IV_TRAILER "-----END IV-----" + #define MAC_HEADER "-----BEGIN MAC-----" + #define MAC_TRAILER "-----END MAC-----" + #define PAD_HEADER "-----BEGIN PAD-----" + #define PAD_TRAILER "-----END PAD-----" + #define LAB_HEADER "-----BEGIN KEY LABEL-----" + #define LAB_TRAILER "-----END KEY LABEL-----" + #define PUBKEY_HEADER "-----BEGIN PUB KEY -----" + #define PUBKEY_TRAILER "-----END PUB KEY -----" + #define NS_CERTREQ_HEADER "-----BEGIN NEW CERTIFICATE REQUEST-----" + #define NS_CERTREQ_TRAILER "-----END NEW CERTIFICATE REQUEST-----" + #define NS_CERT_ENC_HEADER "-----BEGIN CERTIFICATE FOR ENCRYPTION-----" + #define NS_CERT_ENC_TRAILER "-----END CERTIFICATE FOR ENCRYPTION-----" + #define NS_CERT_VFY_HEADER "-----BEGIN CERTIFICATE FOR SIGNATURE VERIFICATION-----" + #define NS_CERT_VFY_TRAILER "-----END CERTIFICATE FOR SIGNATURE VERIFICATION-----" + #define NS_SIG_HEADER "-----BEGIN SIGNATURE-----" + #define NS_SIG_TRAILER "-----END SIGNATURE-----" + #define NS_CERT_HEADER "-----BEGIN CERTIFICATE-----" + #define NS_CERT_TRAILER "-----END CERTIFICATE-----" + + /* sample 6 commands */ + typedef enum { + GENERATE_CSR, + ADD_CERT_TO_DB, + SAVE_CERT_TO_HEADER, + ENCRYPT, + DECRYPT, + SIGN, + VERIFY, + UNKNOWN + } CommandType; + + typedef enum { + SYMKEY = 0, + MACKEY = 1, + IV = 2, + MAC = 3, + PAD = 4, + PUBKEY = 5, + LAB = 6, + CERTENC= 7, + CERTVFY= 8, + SIG = 9 + } HeaderType; + + + /* + * Print usage message and exit + */ + static void + Usage(const char *progName) + { + fprintf(stderr, "\nUsage: %s %s %s %s %s %s %s %s %s %s\n\n", + progName, + " -<G|A|H|E|DS|V> -d <dbdirpath> ", + "[-p <dbpwd> | -f <dbpwdfile>] [-z <noisefilename>] [-a <\"\">]", + "-s <subject> -r <csr> | ", + "-n <nickName> -t <trust> -c <cert> [ -r <csr> -u <issuerNickname> [-x <\"\">] -m <serialNumber> ] | ", + "-n <nickName> -b <headerfilename> | ", + "-b <headerfilename> -i <ipfilename> -e <encryptfilename> | ", + "-b <headerfilename> -i <ipfilename> | ", + "-b <headerfilename> -i <ipfilename> | ", + "-b <headerfilename> -e <encryptfilename> -o <opfilename> \n"); + fprintf(stderr, "commands:\n\n"); + fprintf(stderr, "%s %s\n --for generating cert request (for CA also)\n\n", + progName, "-G -s <subject> -r <csr>"); + fprintf(stderr, "%s %s\n --to input and store cert (for CA also)\n\n", + progName, "-A -n <nickName> -t <trust> -c <cert> [ -r <csr> -u <issuerNickname> [-x <\"\">] -m <serialNumber> ]"); + fprintf(stderr, "%s %s\n --to put cert in header\n\n", + progName, "-H -n <nickname> -b <headerfilename> [-v <\"\">]"); + fprintf(stderr, "%s %s\n --to find public key from cert in header and encrypt\n\n", + progName, "-E -b <headerfilename> -i <ipfilename> -e <encryptfilename> "); + fprintf(stderr, "%s %s\n --decrypt using corresponding private key \n\n", + progName, "-D -b <headerfilename> -e <encryptfilename> -o <opfilename>"); + fprintf(stderr, "%s %s\n --Sign using private key \n\n", + progName, "-S -b <headerfilename> -i <infilename> "); + fprintf(stderr, "%s %s\n --Verify using public key \n\n", + progName, "-V -b <headerfilename> -i <ipfilename> "); + fprintf(stderr, "options:\n\n"); + fprintf(stderr, "%-30s - db directory path\n\n", + "-d <dbdirpath>"); + fprintf(stderr, "%-30s - db password [optional]\n\n", + "-p <dbpwd>"); + fprintf(stderr, "%-30s - db password file [optional]\n\n", + "-f <dbpwdfile>"); + fprintf(stderr, "%-30s - noise file name [optional]\n\n", + "-z <noisefilename>"); + fprintf(stderr, "%-30s - input file name\n\n", + "-i <ipfilename>"); + fprintf(stderr, "%-30s - header file name\n\n", + "-b <headerfilename>"); + fprintf(stderr, "%-30s - encrypt file name\n\n", + "-e <encryptfilename>"); + fprintf(stderr, "%-30s - output file name\n\n", + "-o <opfilename>"); + fprintf(stderr, "%-30s - certificate serial number\n\n", + "-m <serialNumber>"); + fprintf(stderr, "%-30s - certificate nickname\n\n", + "-n <nickname>"); + fprintf(stderr, "%-30s - certificate trust\n\n", + "-t <trustargs>"); + fprintf(stderr, "%-30s - certificate issuer nickname\n\n", + "-u <issuerNickname>"); + fprintf(stderr, "%-30s - certificate signing request \n\n", + "-r <csr>"); + fprintf(stderr, "%-30s - generate a self-signed cert [optional]\n\n", + "-x"); + fprintf(stderr, "%-30s - to enable ascii [optional]\n\n", + "-a"); + fprintf(stderr, "%-30s - to save certificate to header file as sig verification [optional]\n\n", + "-v"); + exit(-1); + } + + /* + * Validate the options used for Generate CSR command + */ + static void + ValidateGenerateCSRCommand(const char *progName, + const char *dbdir, + CERTName *subject, + const char *subjectStr, + const char *certReqFileName) + { + PRBool validationFailed = PR_FALSE; + if (!subject) { + PR_fprintf(PR_STDERR, "%s -G -d %s -s: improperly formatted name: \"%s\"\n", + progName, dbdir, subjectStr); + validationFailed = PR_TRUE; + } + if (!certReqFileName) { + PR_fprintf(PR_STDERR, "%s -G -d %s -s %s -r: certificate request file name not found\n", + progName, dbdir, subjectStr); + validationFailed = PR_TRUE; + } + if (validationFailed) { + fprintf(stderr, "\nUsage: %s %s \n\n", progName, + "-G -d <dbdirpath> -s <subject> -r <csr> \n"); + exit(-1); + } + } + + /* + * Validate the options used for Add Cert to DB command + */ + static void + ValidateAddCertToDBCommand(const char *progName, + const char *dbdir, + const char *nickNameStr, + const char *trustStr, + const char *certFileName, + const char *certReqFileName, + const char *issuerNameStr, + const char *serialNumberStr, + PRBool selfsign) + { + PRBool validationFailed = PR_FALSE; + if (!nickNameStr) { + PR_fprintf(PR_STDERR, "%s -A -d %s -n : nick name is missing\n", + progName, dbdir); + validationFailed = PR_TRUE; + } + if (!trustStr) { + PR_fprintf(PR_STDERR, "%s -A -d %s -n %s -t: trust flag is missing\n", + progName, dbdir, nickNameStr); + validationFailed = PR_TRUE; + } + if (!certFileName) { + PR_fprintf(PR_STDERR, "%s -A -d %s -n %s -t %s -c: certificate file name not found\n", + progName, dbdir, nickNameStr, trustStr, serialNumberStr, certReqFileName); + validationFailed = PR_TRUE; + } + if (PR_Access(certFileName, PR_ACCESS_EXISTS) == PR_FAILURE) { + if (!certReqFileName) { + PR_fprintf(PR_STDERR, "%s -A -d %s -n %s -t %s -c %s -r: certificate file or certificate request file is not found\n", + progName, dbdir, nickNameStr, trustStr, certFileName); + validationFailed = PR_TRUE; + } + if (!selfsign && !issuerNameStr) { + PR_fprintf(PR_STDERR, "%s -A -d %s -n %s -t %s -c %s -r %s -u : issuer name is missing\n", + progName, dbdir, nickNameStr, trustStr, certFileName, certReqFileName); + validationFailed = PR_TRUE; + } + if (!serialNumberStr) { + PR_fprintf(PR_STDERR, "%s -A -d %s -n %s -t %s -c %s -r %s -u %s -m : serial number is missing\n", + progName, dbdir, nickNameStr, trustStr, certFileName, certReqFileName, issuerNameStr); + validationFailed = PR_TRUE; + } + } + if (validationFailed) { + fprintf(stderr, "\nUsage: %s %s \n\n", progName, + " -A -d <dbdirpath> -n <nickName> -t <trust> -c <cert> \n"); + fprintf(stderr, " OR\n"); + fprintf(stderr, "\nUsage: %s %s \n\n", progName, + "-A -d <dbdirpath> -n <nickName> -t <trust> -c <cert> -r <csr> -u <issuerNickname> -m <serialNumber> [-x <\"\">] \n"); + exit(-1); + } + } + + /* + * Validate the options used for Save Cert To Header command + */ + static void + ValidateSaveCertToHeaderCommand(const char *progName, + const char *dbdir, + const char *nickNameStr, + const char *headerFileName) + { + PRBool validationFailed = PR_FALSE; + if (!nickNameStr) { + PR_fprintf(PR_STDERR, "%s -S -d %s -n : nick name is missing\n", + progName, dbdir); + validationFailed = PR_TRUE; + } + if (!headerFileName) { + PR_fprintf(PR_STDERR, "%s -S -d %s -n %s -b : header file name is not found\n", + progName, dbdir, nickNameStr); + validationFailed = PR_TRUE; + } + if (validationFailed) { + fprintf(stderr, "\nUsage: %s %s \n\n", progName, + "-S -d <dbdirpath> -n <nickname> -b <headerfilename> [-v <\"\">]\n"); + exit(-1); + } + } + + /* + * Validate the options used for Encrypt command + */ + static void + ValidateEncryptCommand(const char *progName, + const char *dbdir, + const char *nickNameStr, + const char *headerFileName, + const char *inFileName, + const char *encryptedFileName) + { + PRBool validationFailed = PR_FALSE; + if (!nickNameStr) { + PR_fprintf(PR_STDERR, "%s -E -d %s -n : nick name is missing\n", + progName, dbdir); + validationFailed = PR_TRUE; + } + if (!headerFileName) { + PR_fprintf(PR_STDERR, "%s -E -d %s -n %s -b : header file name is not found\n", + progName, dbdir, nickNameStr); + validationFailed = PR_TRUE; + } + if (!inFileName) { + PR_fprintf(PR_STDERR, "%s -E -d %s -n %s -b %s -i : input file name is not found\n", + progName, dbdir, nickNameStr, headerFileName); + validationFailed = PR_TRUE; + } + if (!encryptedFileName) { + PR_fprintf(PR_STDERR, "%s -E -d %s -n %s -b %s -i %s -e : encrypt file name is not found\n", + progName, dbdir, nickNameStr, headerFileName, inFileName); + validationFailed = PR_TRUE; + } + if (validationFailed) { + fprintf(stderr, "\nUsage: %s %s \n\n", progName, + "-E -d <dbdirpath> -b <headerfilename> -i <ipfilename> -e <encryptfilename> -n <nickname> \n"); + exit(-1); + } + } + + /* + * Validate the options used for Sign command + */ + static void + ValidateSignCommand(const char *progName, + const char *dbdir, + const char *nickNameStr, + const char *headerFileName, + const char *inFileName) + { + PRBool validationFailed = PR_FALSE; + if (!nickNameStr) { + PR_fprintf(PR_STDERR, "%s -I -d %s -n : nick name is missing\n", + progName, dbdir); + validationFailed = PR_TRUE; + } + if (!headerFileName) { + PR_fprintf(PR_STDERR, "%s -I -d %s -n %s -b : header file name is not found\n", + progName, dbdir, nickNameStr); + validationFailed = PR_TRUE; + } + if (!inFileName) { + PR_fprintf(PR_STDERR, "%s -I -d %s -n %s -b %s -i : input file name is not found\n", + progName, dbdir, nickNameStr, headerFileName); + validationFailed = PR_TRUE; + } + if (validationFailed) { + fprintf(stderr, "\nUsage: %s %s \n\n", progName, + "-I -d <dbdirpath> -b <headerfilename> -i <ipfilename> -n <nickname> \n"); + exit(-1); + } + } + + /* + * Validate the options used for verify command + */ + static void + ValidateVerifyCommand(const char *progName, + const char *dbdir, + const char *headerFileName, + const char *inFileName) + { + PRBool validationFailed = PR_FALSE; + if (!headerFileName) { + PR_fprintf(PR_STDERR, "%s -V -d %s -b : header file name is not found\n", + progName, dbdir); + validationFailed = PR_TRUE; + } + if (!inFileName) { + PR_fprintf(PR_STDERR, "%s -I -d %s -b %s -i : input file name is not found\n", + progName, dbdir, headerFileName); + validationFailed = PR_TRUE; + } + if (validationFailed) { + fprintf(stderr, "\nUsage: %s %s \n\n", progName, + "-I -d <dbdirpath> -b <headerfilename> -i <ipfilename> \n"); + exit(-1); + } + } + + /* + * Validate the options used for Decrypt command + */ + static void + ValidateDecryptCommand(const char *progName, + const char *dbdir, + const char *headerFileName, + const char *encryptedFileName, + const char *outFileName) + { + PRBool validationFailed = PR_FALSE; + if (!headerFileName) { + PR_fprintf(PR_STDERR, "%s -D -d %s -b : header file name is not found\n", + progName, dbdir); + validationFailed = PR_TRUE; + } + if (!encryptedFileName) { + PR_fprintf(PR_STDERR, "%s -D -d %s -b %s -e : encrypt file name is not found\n", + progName, dbdir, headerFileName); + validationFailed = PR_TRUE; + } + if (!outFileName) { + PR_fprintf(PR_STDERR, "%s -D -d %s -b %s -e %s -o : output file name is not found\n", + progName, dbdir, headerFileName, encryptedFileName); + validationFailed = PR_TRUE; + } + if (validationFailed) { + fprintf(stderr, "\nUsage: %s %s \n\n", progName, + "-D -d <dbdirpath> -b <headerfilename> -e <encryptfilename> -o <opfilename>\n"); + exit(-1); + } + } + + /* + * Sign the contents of input file using private key and + * return result as SECItem + */ + SECStatus + SignData(const char *inFileName, SECKEYPrivateKey *pk, SECItem *res) + { + SECStatus rv = SECFailure; + unsigned int nb; + unsigned char ibuf[4096]; + PRFileDesc *inFile = NULL; + SGNContext *sgn = NULL; + + /* Open the input file for reading */ + inFile = PR_Open(inFileName, PR_RDONLY, 0); + if (!inFile) { + PR_fprintf(PR_STDERR, "Unable to open \"%s\" for reading.\n", + inFileName); + rv = SECFailure; + goto cleanup; + } + + /* Sign using private key */ + + sgn = SGN_NewContext(SEC_OID_PKCS1_MD5_WITH_RSA_ENCRYPTION, pk); + if (!sgn) { + PR_fprintf(PR_STDERR, "unable to create context for signing\n"); + rv = SECFailure; + goto cleanup; + } + + rv = SGN_Begin(sgn); + if (rv != SECSuccess) { + PR_fprintf(PR_STDERR, "problem while SGN_Begin\n"); + goto cleanup; + } + while ((nb = PR_Read(inFile, ibuf, sizeof(ibuf))) > 0) { + rv = SGN_Update(sgn, ibuf, nb); + if (rv != SECSuccess) { + PR_fprintf(PR_STDERR, "problem while SGN_Update\n"); + goto cleanup; + } + } + rv = SGN_End(sgn, res); + if (rv != SECSuccess) { + PR_fprintf(PR_STDERR, "problem while SGN_End\n"); + goto cleanup; + } + cleanup: + if (inFile) { + PR_Close(inFile); + } + if (sgn) { + SGN_DestroyContext(sgn, PR_TRUE); + } + return rv; + } + + /* + * Verify the signature using public key + */ + SECStatus + VerifyData(const char *inFileName, SECKEYPublicKey *pk, + SECItem *sigItem, secuPWData *pwdata) + { + unsigned int nb; + unsigned char ibuf[4096]; + SECStatus rv = SECFailure; + VFYContext *vfy = NULL; + PRFileDesc *inFile = NULL; + + /* Open the input file for reading */ + inFile = PR_Open(inFileName, PR_RDONLY, 0); + if (!inFile) { + PR_fprintf(PR_STDERR, "Unable to open \"%s\" for reading.\n", + inFileName); + rv = SECFailure; + goto cleanup; + } + + vfy = VFY_CreateContext(pk, + sigItem, + SEC_OID_PKCS1_MD5_WITH_RSA_ENCRYPTION, + pwdata); + if (!vfy) { + PR_fprintf(PR_STDERR, "unable to create context for verifying signature\n"); + rv = SECFailure; + goto cleanup; + } + rv = VFY_Begin(vfy); + if (rv != SECSuccess) { + PR_fprintf(PR_STDERR, "problem while VFY_Begin\n"); + goto cleanup; + } + while ((nb = PR_Read(inFile, ibuf, sizeof(ibuf))) > 0) { + rv = VFY_Update(vfy, ibuf, nb); + if (rv != SECSuccess) { + PR_fprintf(PR_STDERR, "problem while VFY_Update\n"); + goto cleanup; + } + } + rv = VFY_End(vfy); + if (rv != SECSuccess) { + PR_fprintf(PR_STDERR, "problem while VFY_End\n"); + goto cleanup; + } + + cleanup: + if (inFile) { + PR_Close(inFile); + } + if (vfy) { + VFY_DestroyContext(vfy, PR_TRUE); + } + return rv; + } + + /* + * Write Cryptographic parameters to header file + */ + SECStatus + WriteToHeaderFile(const char *buf, unsigned int len, HeaderType type, + PRFileDesc *outFile) + { + SECStatus rv; + const char *header; + const char *trailer; + + switch (type) { + case SYMKEY: + header = ENCKEY_HEADER; + trailer = ENCKEY_TRAILER; + break; + case MACKEY: + header = MACKEY_HEADER; + trailer = MACKEY_TRAILER; + break; + case IV: + header = IV_HEADER; + trailer = IV_TRAILER; + break; + case MAC: + header = MAC_HEADER; + trailer = MAC_TRAILER; + break; + case PAD: + header = PAD_HEADER; + trailer = PAD_TRAILER; + break; + case PUBKEY: + header = PUBKEY_HEADER; + trailer = PUBKEY_TRAILER; + break; + case CERTENC: + header = NS_CERT_ENC_HEADER; + trailer = NS_CERT_ENC_TRAILER; + break; + case CERTVFY: + header = NS_CERT_VFY_HEADER; + trailer = NS_CERT_VFY_TRAILER; + break; + case SIG: + header = NS_SIG_HEADER; + trailer = NS_SIG_TRAILER; + break; + case LAB: + header = LAB_HEADER; + trailer = LAB_TRAILER; + PR_fprintf(outFile, "%s\n", header); + PR_fprintf(outFile, "%s\n", buf); + PR_fprintf(outFile, "%s\n\n", trailer); + return SECSuccess; + break; + default: + return SECFailure; + } + + PR_fprintf(outFile, "%s\n", header); + PrintAsHex(outFile, buf, len); + PR_fprintf(outFile, "%s\n\n", trailer); + return SECSuccess; + } + + /* + * Read cryptographic parameters from the header file + */ + SECStatus + ReadFromHeaderFile(const char *fileName, HeaderType type, + SECItem *item, PRBool isHexData) + { + SECStatus rv = SECSuccess; + PRFileDesc* file = NULL; + SECItem filedata; + SECItem outbuf; + unsigned char *nonbody; + unsigned char *body; + char *header; + char *trailer; + + outbuf.type = siBuffer; + file = PR_Open(fileName, PR_RDONLY, 0); + if (!file) { + PR_fprintf(PR_STDERR, "Failed to open %s\n", fileName); + rv = SECFailure; + goto cleanup; + } + switch (type) { + case PUBKEY: + header = PUBKEY_HEADER; + trailer = PUBKEY_TRAILER; + break; + case SYMKEY: + header = ENCKEY_HEADER; + trailer = ENCKEY_TRAILER; + break; + case MACKEY: + header = MACKEY_HEADER; + trailer = MACKEY_TRAILER; + break; + case IV: + header = IV_HEADER; + trailer = IV_TRAILER; + break; + case MAC: + header = MAC_HEADER; + trailer = MAC_TRAILER; + break; + case PAD: + header = PAD_HEADER; + trailer = PAD_TRAILER; + break; + case LAB: + header = LAB_HEADER; + trailer = LAB_TRAILER; + break; + case CERTENC: + header = NS_CERT_ENC_HEADER; + trailer = NS_CERT_ENC_TRAILER; + break; + case CERTVFY: + header = NS_CERT_VFY_HEADER; + trailer = NS_CERT_VFY_TRAILER; + break; + case SIG: + header = NS_SIG_HEADER; + trailer = NS_SIG_TRAILER; + break; + default: + rv = SECFailure; + goto cleanup; + } + + rv = FileToItem(&filedata, file); + nonbody = (char *)filedata.data; + if (!nonbody) { + PR_fprintf(PR_STDERR, "unable to read data from input file\n"); + rv = SECFailure; + goto cleanup; + } + + /* check for headers and trailers and remove them */ + if ((body = strstr(nonbody, header)) != NULL) { + char *trail = NULL; + nonbody = body; + body = PORT_Strchr(body, '\n'); + if (!body) + body = PORT_Strchr(nonbody, '\r'); /* maybe this is a MAC file */ + if (body) + trail = strstr(++body, trailer); + if (trail != NULL) { + *trail = '\0'; + } else { + PR_fprintf(PR_STDERR, "input has header but no trailer\n"); + PORT_Free(filedata.data); + rv = SECFailure; + goto cleanup; + } + } else { + /* headers didn't exist */ + char *trail = NULL; + body = nonbody; + if (body) { + trail = strstr(++body, trailer); + if (trail != NULL) { + PR_fprintf(PR_STDERR, "input has no header but has trailer\n"); + PORT_Free(filedata.data); + rv = SECFailure; + goto cleanup; + } + } + } + HexToBuf(body, item, isHexData); + cleanup: + if (file) { + PR_Close(file); + } + return rv; + } + + /* + * Generate the private key + */ + SECKEYPrivateKey * + GeneratePrivateKey(KeyType keytype, PK11SlotInfo *slot, int size, + int publicExponent, const char *noise, + SECKEYPublicKey **pubkeyp, const char *pqgFile, + secuPWData *pwdata) + { + CK_MECHANISM_TYPE mechanism; + SECOidTag algtag; + PK11RSAGenParams rsaparams; + void *params; + SECKEYPrivateKey *privKey = NULL; + SECStatus rv; + unsigned char randbuf[BLOCKSIZE + 1]; + + rv = GenerateRandom(randbuf, BLOCKSIZE); + if (rv != SECSuccess) { + fprintf(stderr, "Error while generating the random numbers : %s\n", + PORT_ErrorToString(rv)); + goto cleanup; + } + PK11_RandomUpdate(randbuf, BLOCKSIZE); + switch (keytype) { + case rsaKey: + rsaparams.keySizeInBits = size; + rsaparams.pe = publicExponent; + mechanism = CKM_RSA_PKCS_KEY_PAIR_GEN; + algtag = SEC_OID_PKCS1_MD5_WITH_RSA_ENCRYPTION; + params = &rsaparams; + break; + default: + goto cleanup; + } + fprintf(stderr, "\n\n"); + fprintf(stderr, "Generating key. This may take a few moments...\n\n"); + privKey = PK11_GenerateKeyPair(slot, mechanism, params, pubkeyp, + PR_TRUE /*isPerm*/, PR_TRUE /*isSensitive*/, + pwdata); + cleanup: + return privKey; + } + + /* + * Get the certificate request from CSR + */ + static CERTCertificateRequest * + GetCertRequest(char *inFileName, PRBool ascii) + { + CERTSignedData signedData; + SECItem reqDER; + CERTCertificateRequest *certReq = NULL; + SECStatus rv = SECSuccess; + PRArenaPool *arena = NULL; + + reqDER.data = NULL; + arena = PORT_NewArena(DER_DEFAULT_CHUNKSIZE); + if (arena == NULL) { + rv = SECFailure; + goto cleanup; + } + + rv = ReadDERFromFile(&reqDER, inFileName, ascii); + if (rv) { + rv = SECFailure; + goto cleanup; + } + certReq = (CERTCertificateRequest*) PORT_ArenaZAlloc + (arena, sizeof(CERTCertificateRequest)); + if (!certReq) { + rv = SECFailure; + goto cleanup; + } + certReq->arena = arena; + + /* Since cert request is a signed data, must decode to get the inner data */ + PORT_Memset(&signedData, 0, sizeof(signedData)); + rv = SEC_ASN1DecodeItem(arena, &signedData, + SEC_ASN1_GET(CERT_SignedDataTemplate), &reqDER); + if (rv) { + rv = SECFailure; + goto cleanup; + } + rv = SEC_ASN1DecodeItem(arena, certReq, + SEC_ASN1_GET(CERT_CertificateRequestTemplate), &signedData.data); + if (rv) { + rv = SECFailure; + goto cleanup; + } + rv = CERT_VerifySignedDataWithPublicKeyInfo(&signedData, + &certReq->subjectPublicKeyInfo, NULL /* wincx */); + if (reqDER.data) { + SECITEM_FreeItem(&reqDER, PR_FALSE); + } + + cleanup: + if (rv) { + PR_fprintf(PR_STDERR, "bad certificate request\n"); + if (arena) { + PORT_FreeArena(arena, PR_FALSE); + } + certReq = NULL; + } + return certReq; + } + + /* + * Sign Cert + */ + static SECItem * + SignCert(CERTCertDBHandle *handle, CERTCertificate *cert, + PRBool selfsign, SECOidTag hashAlgTag, + SECKEYPrivateKey *privKey, char *issuerNickName, void *pwarg) + { + SECItem der; + SECStatus rv; + SECOidTag algID; + void *dummy; + PRArenaPool *arena = NULL; + SECItem *result = NULL; + SECKEYPrivateKey *caPrivateKey = NULL; + + if (!selfsign) { + CERTCertificate *issuer = PK11_FindCertFromNickname(issuerNickName, pwarg); + if ((CERTCertificate *)NULL == issuer) { + PR_fprintf(PR_STDERR, "unable to find issuer with nickname %s\n", + issuerNickName); + goto cleanup; + } + privKey = caPrivateKey = PK11_FindKeyByAnyCert(issuer, pwarg); + CERT_DestroyCertificate(issuer); + if (caPrivateKey == NULL) { + PR_fprintf(PR_STDERR, "unable to retrieve key %s\n", + issuerNickName); + goto cleanup; + } + } + arena = cert->arena; + algID = SEC_GetSignatureAlgorithmOidTag(privKey->keyType, hashAlgTag); + if (algID == SEC_OID_UNKNOWN) { + PR_fprintf(PR_STDERR, "Unknown key or hash type for issuer.\n"); + goto cleanup; + } + rv = SECOID_SetAlgorithmID(arena, &cert->signature, algID, 0); + if (rv != SECSuccess) { + PR_fprintf(PR_STDERR, "Could not set signature algorithm id.\n%s\n", + PORT_ErrorToString(rv)); + goto cleanup; + } + + /* we only deal with cert v3 here */ + *(cert->version.data) = 2; + cert->version.len = 1; + + der.len = 0; + der.data = NULL; + dummy = SEC_ASN1EncodeItem (arena, &der, cert, + SEC_ASN1_GET(CERT_CertificateTemplate)); + if (!dummy) { + PR_fprintf(PR_STDERR, "Could not encode certificate.\n"); + goto cleanup; + } + + result = (SECItem *) PORT_ArenaZAlloc (arena, sizeof (SECItem)); + if (result == NULL) { + PR_fprintf(PR_STDERR, "Could not allocate item for certificate data.\n"); + goto cleanup; + } + + rv = SEC_DerSignData(arena, result, der.data, der.len, privKey, algID); + if (rv != SECSuccess) { + PR_fprintf(PR_STDERR, "Could not sign encoded certificate data : %s\n", + PORT_ErrorToString(rv)); + /* result allocated out of the arena, it will be freed + * when the arena is freed */ + result = NULL; + goto cleanup; + } + cert->derCert = *result; + cleanup: + if (caPrivateKey) { + SECKEY_DestroyPrivateKey(caPrivateKey); + } + return result; + } + + /* + * MakeV1Cert + */ + static CERTCertificate * + MakeV1Cert(CERTCertDBHandle *handle, + CERTCertificateRequest *req, + char * issuerNickName, + PRBool selfsign, + unsigned int serialNumber, + int warpmonths, + int validityMonths) + { + PRExplodedTime printableTime; + PRTime now; + PRTime after; + CERTValidity *validity = NULL; + CERTCertificate *issuerCert = NULL; + CERTCertificate *cert = NULL; + + if ( !selfsign ) { + issuerCert = CERT_FindCertByNicknameOrEmailAddr(handle, issuerNickName); + if (!issuerCert) { + PR_fprintf(PR_STDERR, "could not find certificate named %s\n", + issuerNickName); + goto cleanup; + } + } + + now = PR_Now(); + PR_ExplodeTime (now, PR_GMTParameters, &printableTime); + if ( warpmonths ) { + printableTime.tm_month += warpmonths; + now = PR_ImplodeTime (&printableTime); + PR_ExplodeTime (now, PR_GMTParameters, &printableTime); + } + printableTime.tm_month += validityMonths; + after = PR_ImplodeTime (&printableTime); + + /* note that the time is now in micro-second unit */ + validity = CERT_CreateValidity (now, after); + if (validity) { + cert = CERT_CreateCertificate(serialNumber, + (selfsign ? &req->subject : &issuerCert->subject), + validity, req); + + CERT_DestroyValidity(validity); + } + cleanup: + if ( issuerCert ) { + CERT_DestroyCertificate (issuerCert); + } + return cert; + } + + /* + * Add a certificate to the nss database + */ + SECStatus + AddCert(PK11SlotInfo *slot, CERTCertDBHandle *handle, + const char *name, char *trusts, char *inFileName, + PRBool ascii, PRBool emailcert, void *pwdata) + { + SECItem certDER; + SECStatus rv; + CERTCertTrust *trust = NULL; + CERTCertificate *cert = NULL; + + certDER.data = NULL; + + /* Read in the entire file specified with the -i argument */ + rv = ReadDERFromFile(&certDER, inFileName, ascii); + if (rv != SECSuccess) { + PR_fprintf(PR_STDERR, "unable to read input file %s : %s\n", + inFileName, PORT_ErrorToString(rv)); + goto cleanup; + } + + /* Read in an ASCII cert and return a CERTCertificate */ + cert = CERT_DecodeCertFromPackage((char *)certDER.data, certDER.len); + if (!cert) { + PR_fprintf(PR_STDERR, "could not obtain certificate from file\n"); + rv = SECFailure; + goto cleanup; + } + + /* Create a cert trust */ + trust = (CERTCertTrust *)PORT_ZAlloc(sizeof(CERTCertTrust)); + if (!trust) { + PR_fprintf(PR_STDERR, "unable to allocate cert trust\n"); + rv = SECFailure; + goto cleanup; + } + + rv = CERT_DecodeTrustString(trust, trusts); + if (rv) { + PR_fprintf(PR_STDERR, "unable to decode trust string\n"); + rv = SECFailure; + goto cleanup; + } + + rv = PK11_ImportCert(slot, cert, CK_INVALID_HANDLE, name, PR_FALSE); + if (rv != SECSuccess) { + /* sigh, PK11_Import Cert and CERT_ChangeCertTrust should have + * been coded to take a password arg. */ + if (PORT_GetError() == SEC_ERROR_TOKEN_NOT_LOGGED_IN) { + rv = PK11_Authenticate(slot, PR_TRUE, pwdata); + if (rv != SECSuccess) { + PR_fprintf(PR_STDERR, "could not authenticate to token %s : %s\n", + PK11_GetTokenName(slot), PORT_ErrorToString(rv)); + rv = SECFailure; + goto cleanup; + } + rv = PK11_ImportCert(slot, cert, CK_INVALID_HANDLE, + name, PR_FALSE); + } + if (rv != SECSuccess) { + PR_fprintf(PR_STDERR, + "could not add certificate to token or database : %s\n", + PORT_ErrorToString(rv)); + rv = SECFailure; + goto cleanup; + } + } + rv = CERT_ChangeCertTrust(handle, cert, trust); + if (rv != SECSuccess) { + if (PORT_GetError() == SEC_ERROR_TOKEN_NOT_LOGGED_IN) { + rv = PK11_Authenticate(slot, PR_TRUE, pwdata); + if (rv != SECSuccess) { + PR_fprintf(PR_STDERR, "could not authenticate to token %s : %s\n", + PK11_GetTokenName(slot), PORT_ErrorToString(rv)); + rv = SECFailure; + goto cleanup; + } + rv = CERT_ChangeCertTrust(handle, cert, trust); + } + if (rv != SECSuccess) { + PR_fprintf(PR_STDERR, "could not change trust on certificate : %s\n", + PORT_ErrorToString(rv)); + rv = SECFailure; + goto cleanup; + } + } + + if (emailcert) { + CERT_SaveSMimeProfile(cert, NULL, pwdata); + } + + cleanup: + if (cert) { + CERT_DestroyCertificate (cert); + } + if (trust) { + PORT_Free(trust); + } + if (certDER.data) { + PORT_Free(certDER.data); + } + return rv; + } + + /* + * Create a certificate + */ + static SECStatus + CreateCert( + CERTCertDBHandle *handle, + PK11SlotInfo *slot, + char * issuerNickName, + char *inFileName, + char *outFileName, + SECKEYPrivateKey **selfsignprivkey, + void *pwarg, + SECOidTag hashAlgTag, + unsigned int serialNumber, + int warpmonths, + int validityMonths, + const char *dnsNames, + PRBool ascii, + PRBool selfsign) + { + void *extHandle; + SECItem reqDER; + CERTCertExtension **CRexts; + SECStatus rv = SECSuccess; + CERTCertificate *subjectCert = NULL; + CERTCertificateRequest *certReq = NULL; + PRFileDesc *outFile = NULL; + SECItem *certDER = NULL; + + reqDER.data = NULL; + outFile = PR_Open(outFileName, + PR_RDWR | PR_CREATE_FILE | PR_TRUNCATE, 00660); + + /* Create a cert request object from the input cert request der */ + certReq = GetCertRequest(inFileName, ascii); + if (certReq == NULL) { + rv = SECFailure; + goto cleanup; + } + subjectCert = MakeV1Cert(handle, certReq, issuerNickName, selfsign, + serialNumber, warpmonths, validityMonths); + if (subjectCert == NULL) { + rv = SECFailure; + goto cleanup; + } + + extHandle = CERT_StartCertExtensions (subjectCert); + if (extHandle == NULL) { + rv = SECFailure; + goto cleanup; + } + + if (certReq->attributes != NULL && + certReq->attributes[0] != NULL && + certReq->attributes[0]->attrType.data != NULL && + certReq->attributes[0]->attrType.len > 0 && + SECOID_FindOIDTag(&certReq->attributes[0]->attrType) + == SEC_OID_PKCS9_EXTENSION_REQUEST) { + rv = CERT_GetCertificateRequestExtensions(certReq, &CRexts); + if (rv != SECSuccess) { + PR_fprintf(PR_STDERR, "%s\n", PORT_ErrorToString(rv)); + goto cleanup; + } + rv = CERT_MergeExtensions(extHandle, CRexts); + if (rv != SECSuccess) { + PR_fprintf(PR_STDERR, "%s\n", PORT_ErrorToString(rv)); + goto cleanup; + } + } + + CERT_FinishExtensions(extHandle); + + /* self-signing a cert request, find the private key */ + if (*selfsignprivkey == NULL) { + *selfsignprivkey = PK11_FindKeyByDERCert(slot, subjectCert, pwarg); + if (!*selfsignprivkey) { + PR_fprintf(PR_STDERR, "Failed to locate private key.\n"); + rv = SECFailure; + goto cleanup; + } + } + + certDER = SignCert(handle, subjectCert, selfsign, hashAlgTag, + *selfsignprivkey, issuerNickName,pwarg); + if (certDER) { + if (ascii) { + PR_fprintf(outFile, "%s\n%s\n%s\n", NS_CERT_HEADER, + BTOA_DataToAscii(certDER->data, certDER->len), + NS_CERT_TRAILER); + } else { + PR_Write(outFile, certDER->data, certDER->len); + } + } + if (rv != SECSuccess) { + PRErrorCode perr = PR_GetError(); + PR_fprintf(PR_STDERR, "unable to create cert %s\n", + perr); + } + cleanup: + if (outFile) { + PR_Close(outFile); + } + if (*selfsignprivkey) { + SECKEY_DestroyPrivateKey(*selfsignprivkey); + } + if (certReq) { + CERT_DestroyCertificateRequest(certReq); + } + if (subjectCert) { + CERT_DestroyCertificate(subjectCert); + } + return rv; + } + + /* + * Generate the certificate request with subject + */ + static SECStatus + CertReq(SECKEYPrivateKey *privk, SECKEYPublicKey *pubk, KeyType keyType, + SECOidTag hashAlgTag, CERTName *subject, PRBool ascii, + const char *certReqFileName) + { + SECOidTag signAlgTag; + SECItem result; + PRInt32 numBytes; + SECStatus rv = SECSuccess; + PRArenaPool *arena = NULL; + void *extHandle = NULL; + PRFileDesc *outFile = NULL; + CERTSubjectPublicKeyInfo *spki = NULL; + CERTCertificateRequest *cr = NULL; + SECItem *encoding = NULL; + + /* If the certificate request file already exists, delete it */ + if (PR_Access(certReqFileName, PR_ACCESS_EXISTS) == PR_SUCCESS) { + PR_Delete(certReqFileName); + } + /* Open the certificate request file to write */ + outFile = PR_Open(certReqFileName, PR_CREATE_FILE | PR_RDWR | PR_TRUNCATE, 00660); + if (!outFile) { + PR_fprintf(PR_STDERR, + "unable to open \"%s\" for writing (%ld, %ld).\n", + certReqFileName, PR_GetError(), PR_GetOSError()); + goto cleanup; + } + /* Create info about public key */ + spki = SECKEY_CreateSubjectPublicKeyInfo(pubk); + if (!spki) { + PR_fprintf(PR_STDERR, "unable to create subject public key\n"); + rv = SECFailure; + goto cleanup; + } + + /* Generate certificate request */ + cr = CERT_CreateCertificateRequest(subject, spki, NULL); + if (!cr) { + PR_fprintf(PR_STDERR, "unable to make certificate request\n"); + rv = SECFailure; + goto cleanup; + } + + arena = PORT_NewArena(DER_DEFAULT_CHUNKSIZE); + if (!arena) { + fprintf(stderr, "out of memory"); + rv = SECFailure; + goto cleanup; + } + + extHandle = CERT_StartCertificateRequestAttributes(cr); + if (extHandle == NULL) { + PORT_FreeArena (arena, PR_FALSE); + rv = SECFailure; + goto cleanup; + } + + CERT_FinishExtensions(extHandle); + CERT_FinishCertificateRequestAttributes(cr); + + /* Der encode the request */ + encoding = SEC_ASN1EncodeItem(arena, NULL, cr, + SEC_ASN1_GET(CERT_CertificateRequestTemplate)); + if (encoding == NULL) { + PR_fprintf(PR_STDERR, "der encoding of request failed\n"); + rv = SECFailure; + goto cleanup; + } + + /* Sign the request */ + signAlgTag = SEC_GetSignatureAlgorithmOidTag(keyType, hashAlgTag); + if (signAlgTag == SEC_OID_UNKNOWN) { + PR_fprintf(PR_STDERR, "unknown Key or Hash type\n"); + rv = SECFailure; + goto cleanup; + } + rv = SEC_DerSignData(arena, &result, encoding->data, encoding->len, + privk, signAlgTag); + if (rv) { + PR_fprintf(PR_STDERR, "signing of data failed\n"); + rv = SECFailure; + goto cleanup; + } + + /* 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) { + name = 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, "Common Name: %s\n", name); + PR_fprintf(outFile, "Email: %s\n", email); + PR_fprintf(outFile, "Organization: %s\n", org); + PR_fprintf(outFile, "State: %s\n", state); + PR_fprintf(outFile, "Country: %s\n\n", country); + + PR_fprintf(outFile, "%s\n", NS_CERTREQ_HEADER); + numBytes = PR_Write(outFile, obuf, total); + if (numBytes != total) { + PR_fprintf(PR_STDERR, "write error\n"); + return SECFailure; + } + PR_fprintf(outFile, "\n%s\n", NS_CERTREQ_TRAILER); + } else { + numBytes = PR_Write(outFile, result.data, result.len); + if (numBytes != (int)result.len) { + PR_fprintf(PR_STDERR, "write error\n"); + rv = SECFailure; + goto cleanup; + } + } + cleanup: + if (outFile) { + PR_Close(outFile); + } + if (privk) { + SECKEY_DestroyPrivateKey(privk); + } + if (pubk) { + SECKEY_DestroyPublicKey(pubk); + } + return rv; + } + + /* + * Create certificate request with subject + */ + SECStatus CreateCertRequest(PK11SlotInfo *slot, + secuPWData *pwdata, + CERTName *subject, + char *certReqFileName, + PRBool ascii) + { + SECStatus rv; + SECKEYPrivateKey *privkey = NULL; + SECKEYPublicKey *pubkey = NULL; + KeyType keytype = rsaKey; + int keysize = DEFAULT_KEY_BITS; + int publicExponent = 0x010001; + SECOidTag hashAlgTag = SEC_OID_UNKNOWN; + + privkey = GeneratePrivateKey(keytype, slot, keysize, + publicExponent, NULL, + &pubkey, NULL, pwdata); + if (privkey == NULL) { + PR_fprintf(PR_STDERR, "unable to generate key(s)\n"); + rv = SECFailure; + goto cleanup; + } + privkey->wincx = pwdata; + PORT_Assert(pubkey != NULL); + rv = CertReq(privkey, pubkey, keytype, hashAlgTag, subject, + ascii, certReqFileName); + + if (rv != SECSuccess) { + PR_fprintf(PR_STDERR, "Failed to create Certificate Request\n"); + } + cleanup: + return rv; + } + + /* + * Creates the certificate using CSR and adds the certificate to DB + */ + SECStatus AddCertificateToDB(PK11SlotInfo *slot, + secuPWData *pwdata, + char *certReqFileName, + char *certFileName, + char *issuerNameStr, + CERTCertDBHandle *certHandle, + const char *nickNameStr, + char *trustStr, + unsigned int serialNumber, + PRBool selfsign, + PRBool ascii) + { + SECStatus rv; + SECKEYPrivateKey *privkey = NULL; + SECKEYPublicKey *pubkey = NULL; + SECOidTag hashAlgTag = SEC_OID_UNKNOWN; + + if (PR_Access(certFileName, PR_ACCESS_EXISTS) == PR_FAILURE) { + rv = CreateCert(certHandle, slot, issuerNameStr, + certReqFileName, certFileName, &privkey, &pwdata, hashAlgTag, + serialNumber, 0, 3, NULL, ascii, selfsign); + if (rv != SECSuccess) { + PR_fprintf(PR_STDERR, "Failed to create Certificate\n"); + goto cleanup; + } + } + rv = AddCert(slot, certHandle, nickNameStr, + trustStr, certFileName, ascii, 0, &pwdata); + if (rv != SECSuccess) { + PR_fprintf(PR_STDERR, "Failed to add Certificate\n"); + } + cleanup: + return rv; + } + + /* + * Finds the certificate using nickname and saves it to the header file + */ + SECStatus AddCertificateToHeader(PK11SlotInfo *slot, + secuPWData *pwdata, + const char *headerFileName, + CERTCertDBHandle *certHandle, + const char *nickNameStr, + PRBool sigVerify) + + { + SECStatus rv = SECSuccess; + PRFileDesc *headerFile = NULL; + CERTCertificate *cert = NULL; + HeaderType hType = CERTENC; + + /* If the intermediate header file already exists, delete it */ + if (PR_Access(headerFileName, PR_ACCESS_EXISTS) == PR_SUCCESS) { + PR_Delete(headerFileName); + } + headerFile = PR_Open(headerFileName, PR_CREATE_FILE | PR_RDWR | PR_TRUNCATE, 00660); + if (!headerFile) { + PR_fprintf(PR_STDERR, + "unable to open \"%s\" for writing (%ld, %ld).\n", + headerFileName, PR_GetError(), PR_GetOSError()); + rv = SECFailure; + goto cleanup; + } + cert = CERT_FindCertByNicknameOrEmailAddr(certHandle, nickNameStr); + if (!cert) { + PR_fprintf(PR_STDERR, "could not obtain certificate from file\n"); + rv = SECFailure; + goto cleanup; + } + if (sigVerify) { + hType = CERTVFY; + } + WriteToHeaderFile(cert->derCert.data, cert->derCert.len, hType, headerFile); + cleanup: + if (headerFile) { + PR_Close(headerFile); + } + if (cert) { + CERT_DestroyCertificate(cert); + } + return rv; + } + + /* + * Finds the public key from the certificate saved in the header file + * and encrypts with it the contents of inFileName to encryptedFileName. + */ + SECStatus FindKeyAndEncrypt(PK11SlotInfo *slot, + secuPWData *pwdata, + const char *headerFileName, + const char *encryptedFileName, + const char *inFileName) + { + SECStatus rv; + PRFileDesc *headerFile = NULL; + PRFileDesc *encFile = NULL; + PRFileDesc *inFile = NULL; + CERTCertificate *cert = NULL; + SECItem data; + unsigned char ptext[MODBLOCKSIZE]; + unsigned char encBuf[MODBLOCKSIZE]; + unsigned int ptextLen; + int index; + unsigned int nWritten; + unsigned int pad[1]; + SECItem padItem; + unsigned int paddingLength = 0; + SECKEYPublicKey *pubkey = NULL; + + /* If the intermediate encrypted file already exists, delete it*/ + if (PR_Access(encryptedFileName, PR_ACCESS_EXISTS) == PR_SUCCESS) { + PR_Delete(encryptedFileName); + } + + /* Read certificate from header file */ + rv = ReadFromHeaderFile(headerFileName, CERTENC, &data, PR_TRUE); + if (rv != SECSuccess) { + PR_fprintf(PR_STDERR, "Could not read certificate from header file\n"); + goto cleanup; + } + /* Read in an ASCII cert and return a CERTCertificate */ + cert = CERT_DecodeCertFromPackage((char *)data.data, data.len); + if (!cert) { + PR_fprintf(PR_STDERR, "could not obtain certificate from file\n"); + rv = SECFailure; + goto cleanup; + } + /* Extract the public key from certificate */ + pubkey = CERT_ExtractPublicKey(cert); + if (!pubkey) { + PR_fprintf(PR_STDERR, "could not get key from certificate\n"); + rv = SECFailure; + goto cleanup; + } + + /* Open the encrypted file for writing */ + encFile = PR_Open(encryptedFileName, + PR_CREATE_FILE | PR_TRUNCATE | PR_RDWR, 00660); + if (!encFile) { + PR_fprintf(PR_STDERR, + "Unable to open \"%s\" for writing.\n", + encryptedFileName); + rv = SECFailure; + goto cleanup; + } + + /* Open the input file for reading */ + inFile = PR_Open(inFileName, PR_RDONLY, 0); + if (!inFile) { + PR_fprintf(PR_STDERR, "Unable to open \"%s\" for reading.\n", + inFileName); + rv = SECFailure; + goto cleanup; + } + + /* Open the header file to write padding */ + headerFile = PR_Open(headerFileName, PR_CREATE_FILE | PR_RDWR | PR_APPEND, 00660); + if (!headerFile) { + PR_fprintf(PR_STDERR, "Unable to open \"%s\" for writing.\n", + headerFileName); + rv = SECFailure; + goto cleanup; + } + + /* Read input file */ + while ((ptextLen = PR_Read(inFile, ptext, sizeof(ptext))) > 0) { + if (ptextLen != MODBLOCKSIZE) { + paddingLength = MODBLOCKSIZE - ptextLen; + for ( index=0; index < paddingLength; index++) { + ptext[ptextLen+index] = (unsigned char)paddingLength; + } + ptextLen = MODBLOCKSIZE; + } + rv = PK11_PubEncryptRaw(pubkey, encBuf, ptext, ptextLen, NULL); + nWritten = PR_Write(encFile, encBuf, ptextLen); + } + + /* Write the padding to header file */ + pad[0] = paddingLength; + padItem.type = siBuffer; + padItem.data = (unsigned char *)pad; + padItem.len = sizeof(pad[0]); + WriteToHeaderFile(padItem.data, padItem.len, PAD, headerFile); + + cleanup: + if (headerFile) { + PR_Close(headerFile); + } + if (encFile) { + PR_Close(encFile); + } + if (inFile) { + PR_Close(inFile); + } + if (pubkey) { + SECKEY_DestroyPublicKey(pubkey); + } + if (cert) { + CERT_DestroyCertificate(cert); + } + return rv; + } + + /* + * Finds the private key from db and signs the contents + * of inFileName and writes to signatureFileName + */ + SECStatus FindKeyAndSign(PK11SlotInfo *slot, + CERTCertDBHandle* certHandle, + secuPWData *pwdata, + const char *nickNameStr, + const char *headerFileName, + const char *inFileName) + { + SECStatus rv; + PRFileDesc *headerFile = NULL; + PRFileDesc *inFile = NULL; + CERTCertificate *cert = NULL; + unsigned int signatureLen = 0; + SECKEYPrivateKey *privkey = NULL; + SECItem sigItem; + SECOidTag hashOIDTag; + + /* Open the header file to write padding */ + headerFile = PR_Open(headerFileName, PR_CREATE_FILE | PR_RDWR | PR_APPEND, 00660); + if (!headerFile) { + PR_fprintf(PR_STDERR, "Unable to open \"%s\" for writing.\n", + headerFileName); + rv = SECFailure; + goto cleanup; + } + + /* Get the certificate by nick name and write to header file */ + cert = CERT_FindCertByNicknameOrEmailAddr(certHandle, nickNameStr); + if (!cert) { + PR_fprintf(PR_STDERR, "could not obtain certificate by name - %s\n", nickNameStr); + rv = SECFailure; + goto cleanup; + } + WriteToHeaderFile(cert->derCert.data, cert->derCert.len, CERTVFY, headerFile); + + + /* Find private key from certificate */ + privkey = PK11_FindKeyByAnyCert(cert, NULL); + if (privkey == NULL) { + fprintf(stderr, "Couldn't find private key for cert\n"); + rv = SECFailure; + goto cleanup; + } + + /* Sign the contents of the input file */ + rv = SignData(inFileName, privkey, &sigItem); + if (rv != SECSuccess) { + PR_fprintf(PR_STDERR, "could not sign the contents from file - %s \n", inFileName); + goto cleanup; + } + + /* write signature to header file */ + WriteToHeaderFile(sigItem.data, sigItem.len, SIG, headerFile); + + cleanup: + if (headerFile) { + PR_Close(headerFile); + } + if (privkey) { + SECKEY_DestroyPrivateKey(privkey); + } + if (cert) { + CERT_DestroyCertificate(cert); + } + return rv; + } + + /* + * Finds the public key from certificate and verifies signature + */ + SECStatus FindKeyAndVerify(PK11SlotInfo *slot, + CERTCertDBHandle* certHandle, + secuPWData *pwdata, + const char *headerFileName, + const char *inFileName) + { + SECStatus rv = SECFailure; + PRFileDesc *headerFile = NULL; + PRFileDesc *inFile = NULL; + CERTCertificate *cert = NULL; + SECKEYPublicKey *pubkey = NULL; + SECItem sigItem; + SECItem certData; + + + /* Open the input file */ + inFile = PR_Open(inFileName, PR_RDONLY, 0); + if (!inFile) { + PR_fprintf(PR_STDERR, + "Unable to open \"%s\" for reading.\n", + inFileName); + rv = SECFailure; + goto cleanup; + } + + /* Open the header file to read the certificate and signature */ + headerFile = PR_Open(headerFileName, PR_RDONLY, 0); + if (!headerFile) { + PR_fprintf(PR_STDERR, "Unable to open \"%s\" for writing.\n", + headerFileName); + rv = SECFailure; + goto cleanup; + } + + /* Read certificate from header file */ + rv = ReadFromHeaderFile(headerFileName, CERTVFY, &certData, PR_TRUE); + if (rv != SECSuccess) { + PR_fprintf(PR_STDERR, "Could not read certificate from header file\n"); + goto cleanup; + } + + /* Read in an ASCII cert and return a CERTCertificate */ + cert = CERT_DecodeCertFromPackage((char *)certData.data, certData.len); + if (!cert) { + PR_fprintf(PR_STDERR, "could not obtain certificate from file\n"); + rv = SECFailure; + goto cleanup; + } + + /* Extract the public key from certificate */ + pubkey = CERT_ExtractPublicKey(cert); + if (!pubkey) { + PR_fprintf(PR_STDERR, "Could not get key from certificate\n"); + rv = SECFailure; + goto cleanup; + } + + /* Read signature from header file */ + rv = ReadFromHeaderFile(headerFileName, SIG, &sigItem, PR_TRUE); + if (rv != SECSuccess) { + PR_fprintf(PR_STDERR, "Could not read signature from header file\n"); + goto cleanup; + } + + /* Verify with the public key */ + rv = VerifyData(inFileName, pubkey, &sigItem, pwdata); + if (rv != SECSuccess) { + PR_fprintf(PR_STDERR, "Couldn't verify the signature for file - %s\n", inFileName); + goto cleanup; + } + + cleanup: + if (headerFile) { + PR_Close(headerFile); + } + if (pubkey) { + SECKEY_DestroyPublicKey(pubkey); + } + if (cert) { + CERT_DestroyCertificate(cert); + } + return rv; + } + + /* + * Finds the private key corresponding to the certificate saved in the header file + * and decrypts with it the contents of encryptedFileName to outFileName. + */ + SECStatus FindKeyAndDecrypt(PK11SlotInfo *slot, + secuPWData *pwdata, + const char *headerFileName, + const char *encryptedFileName, + const char *outFileName) + { + SECStatus rv; + PRFileDesc *encFile = NULL; + PRFileDesc *outFile = NULL; + SECKEYPrivateKey *pvtkey = NULL; + unsigned int inFileLength = 0; + unsigned int paddingLength = 0; + unsigned int count = 0; + unsigned int temp = 0; + unsigned char ctext[MODBLOCKSIZE]; + unsigned char decBuf[MODBLOCKSIZE]; + unsigned int ctextLen; + unsigned int decBufLen; + SECItem padItem; + SECItem data; + SECItem signature; + CERTCertificate *cert = NULL; + + /* Read certificate from header file */ + rv = ReadFromHeaderFile(headerFileName, CERTENC, &data, PR_TRUE); + if (rv != SECSuccess) { + PR_fprintf(PR_STDERR, "Could not read certificate from header file\n"); + goto cleanup; + } + + /* Read padding from header file */ + rv = ReadFromHeaderFile(headerFileName, PAD, &padItem, PR_TRUE); + if (rv != SECSuccess) { + PR_fprintf(PR_STDERR, + "Could not retrieve PAD detail from header file\n"); + goto cleanup; + } + paddingLength = (unsigned int)padItem.data[0]; + inFileLength = FileSize(encryptedFileName); + + /* Read in an ASCII cert and return a CERTCertificate */ + cert = CERT_DecodeCertFromPackage((char *)data.data, data.len); + if (!cert) { + PR_fprintf(PR_STDERR, "could not obtain certificate from file\n"); + rv = SECFailure; + goto cleanup; + } + + /* Find private key from certificate */ + pvtkey = PK11_FindKeyByAnyCert(cert, NULL); + if (pvtkey == NULL) { + fprintf(stderr, "Couldn't find private key for cert\n"); + rv = SECFailure; + goto cleanup; + } + + /* Open the out file to write */ + outFile = PR_Open(outFileName, + PR_CREATE_FILE | PR_TRUNCATE | PR_RDWR, 00660); + if (!outFile) { + PR_fprintf(PR_STDERR, "Unable to open \"%s\" for writing.\n", + outFileName); + rv = SECFailure; + goto cleanup; + } + /* Open the encrypted file for reading */ + encFile = PR_Open(encryptedFileName, PR_RDONLY, 0); + if (!encFile) { + PR_fprintf(PR_STDERR, "Unable to open \"%s\" for reading.\n", + encryptedFileName); + rv = SECFailure; + goto cleanup; + } + /* Read the encrypt file, decrypt and write to out file */ + while ((ctextLen = PR_Read(encFile, ctext, sizeof(ctext))) > 0) { + count += ctextLen; + rv = PK11_PubDecryptRaw(pvtkey, decBuf, &decBufLen, sizeof(decBuf), ctext, ctextLen); + if (rv != SECSuccess) { + fprintf(stderr, "Couldn't decrypt\n"); + goto cleanup; + } + if (decBufLen == 0) { + break; + } + if (count == inFileLength) { + decBufLen = decBufLen - paddingLength; + } + /* write the plain text to out file */ + temp = PR_Write(outFile, decBuf, decBufLen); + if (temp != decBufLen) { + PR_fprintf(PR_STDERR, "write error\n"); + rv = SECFailure; + break; + } + } + cleanup: + if (encFile) { + PR_Close(encFile); + } + if (outFile) { + PR_Close(outFile); + } + if (pvtkey) { + SECKEY_DestroyPrivateKey(pvtkey); + } + if (cert) { + CERT_DestroyCertificate(cert); + } + return rv; + } + + /* Map option letter to command */ + static CommandType option2Command(char c) + { + switch (c) { + case 'G': return GENERATE_CSR; + case 'A': return ADD_CERT_TO_DB; + case 'H': return SAVE_CERT_TO_HEADER; + case 'E': return ENCRYPT; + case 'D': return DECRYPT; + case 'S': return SIGN; + case 'V': return VERIFY; + default: return UNKNOWN; + } + } + + /* + * This example illustrates basic encryption/decryption and MACing + * Generates the RSA key pair as token object and outputs public key as cert request. + * Reads cert request file and stores certificate in DB. + * Input, store and trust CA certificate. + * Write certificate to intermediate header file + * Extract public key from certificate, encrypts the input file and write to external file. + * Finds the matching private key, decrypts and write to external file + * + * How this sample is different from sample 5 ? + * + * 1. As in sample 5, output is a PKCS#10 CSR + * 2. Input and store a cert in cert DB and also used to input, store and trust CA cert. + * 3. Like sample 5, but puts cert in header + * 4. Like sample 5, but finds key matching cert in header + */ + int + main(int argc, char **argv) + { + SECStatus rv; + PLOptState *optstate; + PLOptStatus status; + PRBool initialized = PR_FALSE; + + CommandType cmd = UNKNOWN; + const char *dbdir = NULL; + secuPWData pwdata = { PW_NONE, 0 }; + + char *subjectStr = NULL; + CERTName *subject = 0; + + unsigned int serialNumber = 0; + char *serialNumberStr = NULL; + char *trustStr = NULL; + CERTCertDBHandle *certHandle; + const char *nickNameStr = NULL; + char *issuerNameStr = NULL; + PRBool selfsign = PR_FALSE; + PRBool ascii = PR_FALSE; + PRBool sigVerify = PR_FALSE; + + const char *headerFileName = NULL; + const char *encryptedFileName = NULL; + const char *inFileName = NULL; + const char *outFileName = NULL; + char *certReqFileName = NULL; + char *certFileName = NULL; + const char *noiseFileName = NULL; + PK11SlotInfo *slot = NULL; + + char * progName = strrchr(argv[0], '/'); + progName = progName ? progName + 1 : argv[0]; + + /* Parse command line arguments */ + optstate = PL_CreateOptState(argc, argv, "GAHEDSVad:i:o:f:p:z:s:r:n:x:m:t:c:u:e:b:v:"); + while ((status = PL_GetNextOpt(optstate)) == PL_OPT_OK) { + switch (optstate->option) { + case 'a': + ascii = PR_TRUE; + break; + case 'G': /* Generate a CSR */ + case 'A': /* Add cert to database */ + case 'H': /* Save cert to the header file */ + case 'E': /* Encrypt with public key from cert in header file */ + case 'S': /* Sign with private key */ + case 'D': /* Decrypt with the matching private key */ + case 'V': /* Verify with the matching public key */ + cmd = option2Command(optstate->option); + break; + case 'd': + dbdir = strdup(optstate->value); + break; + case 'f': + pwdata.source = PW_FROMFILE; + pwdata.data = strdup(optstate->value); + break; + case 'p': + pwdata.source = PW_PLAINTEXT; + pwdata.data = strdup(optstate->value); + break; + case 'i': + inFileName = strdup(optstate->value); + break; + case 'b': + headerFileName = strdup(optstate->value); + break; + case 'e': + encryptedFileName = strdup(optstate->value); + break; + case 'o': + outFileName = strdup(optstate->value); + break; + case 'z': + noiseFileName = strdup(optstate->value); + break; + case 's': + subjectStr = strdup(optstate->value); + subject = CERT_AsciiToName(subjectStr); + break; + case 'r': + certReqFileName = strdup(optstate->value); + break; + case 'c': + certFileName = strdup(optstate->value); + break; + case 'u': + issuerNameStr = strdup(optstate->value); + break; + case 'n': + nickNameStr = strdup(optstate->value); + break; + case 'x': + selfsign = PR_TRUE; + break; + case 'm': + serialNumberStr = strdup(optstate->value); + serialNumber = atoi(serialNumberStr); + break; + case 't': + trustStr = strdup(optstate->value); + break; + case 'v': + sigVerify = PR_TRUE; + break; + default: + Usage(progName); + break; + } + } + PL_DestroyOptState(optstate); + + if (cmd == UNKNOWN || !dbdir) + Usage(progName); + + /* Open DB for read/write and authenticate to it */ + PR_Init(PR_USER_THREAD, PR_PRIORITY_NORMAL, 0); + initialized = PR_TRUE; + rv = NSS_InitReadWrite(dbdir); + if (rv != SECSuccess) { + PR_fprintf(PR_STDERR, "NSS_InitReadWrite Failed\n"); + goto cleanup; + } + + PK11_SetPasswordFunc(GetModulePassword); + slot = PK11_GetInternalKeySlot(); + if (PK11_NeedLogin(slot)) { + rv = PK11_Authenticate(slot, PR_TRUE, &pwdata); + if (rv != SECSuccess) { + PR_fprintf(PR_STDERR, "Could not authenticate to token %s.\n", + PK11_GetTokenName(slot)); + goto cleanup; + } + } + + switch (cmd) { + case GENERATE_CSR: + ValidateGenerateCSRCommand(progName, dbdir, subject, subjectStr, + certReqFileName); + /* Generate a CSR */ + rv = CreateCertRequest(slot, &pwdata, subject, + certReqFileName, ascii); + if (rv != SECSuccess) { + PR_fprintf(PR_STDERR, "Create Certificate Request: Failed\n"); + goto cleanup; + } + break; + case ADD_CERT_TO_DB: + ValidateAddCertToDBCommand(progName, dbdir, nickNameStr, trustStr, + certFileName, certReqFileName, + issuerNameStr, serialNumberStr, selfsign); + /* Add cert to database */ + rv = AddCertificateToDB(slot, &pwdata, certReqFileName, certFileName, + issuerNameStr, certHandle, nickNameStr, + trustStr, serialNumber, selfsign, ascii); + if (rv != SECSuccess) { + PR_fprintf(PR_STDERR, "Add Certificate to DB: Failed\n"); + goto cleanup; + } + break; + case SAVE_CERT_TO_HEADER: + ValidateSaveCertToHeaderCommand(progName, dbdir, nickNameStr, headerFileName); + /* Save cert to the header file */ + rv = AddCertificateToHeader(slot, &pwdata, headerFileName, certHandle, nickNameStr, sigVerify); + if (rv != SECSuccess) { + PR_fprintf(PR_STDERR, "Saving Certificate to header: Failed\n"); + goto cleanup; + } + break; + case ENCRYPT: + ValidateEncryptCommand(progName, dbdir, nickNameStr, headerFileName, inFileName, encryptedFileName); + /* Encrypt with public key from cert in header file */ + rv = FindKeyAndEncrypt(slot, &pwdata, headerFileName, encryptedFileName, inFileName); + if (rv != SECSuccess) { + PR_fprintf(PR_STDERR, "Find public key and Encrypt : Failed\n"); + goto cleanup; + } + break; + case SIGN: + ValidateSignCommand(progName, dbdir, nickNameStr, headerFileName, inFileName); + /* Sign with private key */ + rv = FindKeyAndSign(slot, certHandle, &pwdata, nickNameStr, headerFileName, inFileName); + if (rv != SECSuccess) { + PR_fprintf(PR_STDERR, "Find private key and sign : Failed\n"); + goto cleanup; + } + break; + case DECRYPT: + ValidateDecryptCommand(progName, dbdir, headerFileName, encryptedFileName, outFileName); + /* Decrypt with the matching private key */ + rv = FindKeyAndDecrypt(slot, &pwdata, headerFileName, encryptedFileName, outFileName); + if (rv != SECSuccess) { + PR_fprintf(PR_STDERR, "Find private key and Decrypt : Failed\n"); + } + break; + case VERIFY: + ValidateVerifyCommand(progName, dbdir, headerFileName, inFileName); + /* Verify with the matching public key */ + rv = FindKeyAndVerify(slot, certHandle, &pwdata, headerFileName, inFileName); + if (rv != SECSuccess) { + PR_fprintf(PR_STDERR, "Find public key and verify signature : Failed\n"); + goto cleanup; + } + } + cleanup: + if (slot) { + PK11_FreeSlot(slot); + } + if (initialized) { + SECStatus rvShutdown = NSS_Shutdown(); + if (rvShutdown != SECSuccess) { + PR_fprintf(PR_STDERR, "Failed : NSS_Shutdown() - %s", + PORT_ErrorToString(rvShutdown)); + rv = SECFailure; + } + PR_Cleanup(); + } + return rv; + }
\ No newline at end of file |