summaryrefslogtreecommitdiffstats
path: root/security/nss/doc/rst/legacy/nss_sample_code
diff options
context:
space:
mode:
authorDaniel Baumann <daniel.baumann@progress-linux.org>2024-04-07 19:33:14 +0000
committerDaniel Baumann <daniel.baumann@progress-linux.org>2024-04-07 19:33:14 +0000
commit36d22d82aa202bb199967e9512281e9a53db42c9 (patch)
tree105e8c98ddea1c1e4784a60a5a6410fa416be2de /security/nss/doc/rst/legacy/nss_sample_code
parentInitial commit. (diff)
downloadfirefox-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')
-rw-r--r--security/nss/doc/rst/legacy/nss_sample_code/enc_dec_mac_output_plblic_key_as_csr/index.rst1697
-rw-r--r--security/nss/doc/rst/legacy/nss_sample_code/enc_dec_mac_using_key_wrap_certreq_pkcs10_csr/index.rst2090
-rw-r--r--security/nss/doc/rst/legacy/nss_sample_code/encrypt_decrypt_mac_using_token/index.rst1206
-rw-r--r--security/nss/doc/rst/legacy/nss_sample_code/index.rst31
-rw-r--r--security/nss/doc/rst/legacy/nss_sample_code/nss_sample_code_sample1/index.rst713
-rw-r--r--security/nss/doc/rst/legacy/nss_sample_code/nss_sample_code_sample2/index.rst166
-rw-r--r--security/nss/doc/rst/legacy/nss_sample_code/nss_sample_code_sample3/index.rst169
-rw-r--r--security/nss/doc/rst/legacy/nss_sample_code/nss_sample_code_sample4/index.rst158
-rw-r--r--security/nss/doc/rst/legacy/nss_sample_code/nss_sample_code_sample5/index.rst174
-rw-r--r--security/nss/doc/rst/legacy/nss_sample_code/nss_sample_code_sample6/index.rst153
-rw-r--r--security/nss/doc/rst/legacy/nss_sample_code/nss_sample_code_sample_1_hashing/index.rst253
-rw-r--r--security/nss/doc/rst/legacy/nss_sample_code/nss_sample_code_sample_2_initialization_of_nss/index.rst257
-rw-r--r--security/nss/doc/rst/legacy/nss_sample_code/nss_sample_code_sample_3_basic_encryption_and_maci/index.rst1221
-rw-r--r--security/nss/doc/rst/legacy/nss_sample_code/nss_sample_code_utililies_1/index.rst553
-rw-r--r--security/nss/doc/rst/legacy/nss_sample_code/sample1/index.rst230
-rw-r--r--security/nss/doc/rst/legacy/nss_sample_code/sample1_-_hashing/index.rst257
-rw-r--r--security/nss/doc/rst/legacy/nss_sample_code/sample2/index.rst12
-rw-r--r--security/nss/doc/rst/legacy/nss_sample_code/sample2_-_initialize_nss_database/index.rst250
-rw-r--r--security/nss/doc/rst/legacy/nss_sample_code/sample3_-_encdecmac_using_token_object/index.rst30
-rw-r--r--security/nss/doc/rst/legacy/nss_sample_code/utiltiies_for_nss_samples/index.rst747
20 files changed, 10367 insertions, 0 deletions
diff --git a/security/nss/doc/rst/legacy/nss_sample_code/enc_dec_mac_output_plblic_key_as_csr/index.rst b/security/nss/doc/rst/legacy/nss_sample_code/enc_dec_mac_output_plblic_key_as_csr/index.rst
new file mode 100644
index 0000000000..dfa740a911
--- /dev/null
+++ b/security/nss/doc/rst/legacy/nss_sample_code/enc_dec_mac_output_plblic_key_as_csr/index.rst
@@ -0,0 +1,1697 @@
+.. _mozilla_projects_nss_nss_sample_code_enc_dec_mac_output_plblic_key_as_csr:
+
+Enc Dec MAC Output Public Key as CSR
+====================================
+
+.. _nss_sample_code_5_encryptiondecryption_and_mac_and_output_public_as_a_csr.:
+
+`NSS Sample Code 5: Encryption/Decryption and MAC and output Public as a CSR. <#nss_sample_code_5_encryptiondecryption_and_mac_and_output_public_as_a_csr.>`__
+--------------------------------------------------------------------------------------------------------------------------------------------------------------
+
+.. container::
+
+ Generates encryption/mac keys and outputs public key as 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
+ #include
+ #include
+ #include
+ #include
+ #include
+ #include
+
+ /* NSS headers */
+ #include
+ #include
+ #include
+ #include
+ #include
+ #include
+ #include
+ #include
+ #include
+ #include
+ #include
+ #include
+
+ /* our samples utilities */
+ #include "util.h"
+
+ #define BUFFERSIZE 80
+ #define DIGESTSIZE 16
+ #define PTEXT_MAC_BUFFER_SIZE 96
+ #define CIPHERSIZE 96
+ #define BLOCKSIZE 32
+ #define DEFAULT_KEY_BITS 1024
+
+
+ #define CIPHER_HEADER "-----BEGIN CIPHER-----"
+ #define CIPHER_TRAILER "-----END CIPHER-----"
+ #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-----"
+
+
+ typedef enum {
+ GEN_CSR,
+ ENCRYPT,
+ DECRYPT,
+ UNKNOWN
+ } CommandType;
+
+ typedef enum {
+ SYMKEY = 0,
+ MACKEY = 1,
+ IV = 2,
+ MAC = 3,
+ PAD = 4,
+ PUBKEY = 5,
+ LAB = 6
+ } HeaderType;
+
+ /* This is conditionalized because PORT_ErrorToString was introduced with nss 3.13.
+ * Though PR_ErrorToString was available, support for it in nss wasn't.
+ * FIXME: samples should determine the version of nss that's available and refuse
+ * to run if not 3.13 or higher.
+ */
+ #ifndef PORT_ErrorToString
+ #ifndef SEC_ERROR_BASE
+ #define SEC_ERROR_BASE (-0x2000)
+ #define PORT_ErrorToString(err) PR_ErrorToString((err), PR_LANGUAGE_I_DEFAULT)
+ #endif
+ #endif
+
+
+ /*
+ * Print usage message and exit
+ */
+ static void
+ Usage(const char *progName)
+ {
+ fprintf(stderr, "\nUsage: %s -c -d [-z ] "
+ "[-p | -f ] -s -r -i -o \n\n",
+ progName);
+ fprintf(stderr, "%-20s Specify 'G' for generating RSA keypair for wrapping\n\n",
+ "G");
+ fprintf(stderr, "%-20s Specify 'E' for encrypt operation\n\n",
+ "E");
+ fprintf(stderr, "%-20s Specify 'D' for decrypt operation\n\n",
+ "D");
+ fprintf(stderr, "%-20s Specify db directory path\n\n",
+ "-d ");
+ fprintf(stderr, "%-20s Specify db password [optional]\n\n",
+ "-p ");
+ fprintf(stderr, "%-20s Specify db password file [optional]\n\n",
+ "-f ");
+ fprintf(stderr, "%-20s Specify noise file name [optional]\n\n",
+ "-z ");
+ fprintf(stderr, "%-21s Specify subject\n\n",
+ "-s ");
+ fprintf(stderr, "%-21s Specify certficate request file name\n\n",
+ "-r ");
+ fprintf(stderr, "%-21s Specify an input file name\n\n",
+ "-i ");
+ fprintf(stderr, "%-21s Specify an output file name\n\n",
+ "-o ");
+ fprintf(stderr, "%-7s For encrypt, it takes as an input file and produces\n",
+ "Note :");
+ fprintf(stderr, "%-7s .enc and .header as intermediate output files.\n\n",
+ "");
+ fprintf(stderr, "%-7s For decrypt, it takes .enc and .header\n",
+ "");
+ fprintf(stderr, "%-7s as input files and produces as a final output file.\n\n",
+ "");
+ exit(-1);
+ }
+
+
+ /* Map option letter enumerated commad type */
+ static CommandType option2Command(const char* c)
+ {
+ switch (*c) {
+ case 'G': return GEN_CSR;
+ case 'E': return ENCRYPT;
+ case 'D': return DECRYPT;
+ default: return UNKNOWN;
+ }
+ }
+
+ /*
+ * Wrap the symkey using public key
+ */
+ SECStatus
+ WrapKey(PK11SymKey* key, SECKEYPublicKey *pubKey, SECItem **wrappedKey)
+ {
+ SECStatus rv;
+ SECItem *data = (SECItem *)PORT_ZAlloc(sizeof(SECItem));
+
+ if (!data) {
+ PR_fprintf(PR_STDERR, "Error while allocating memory\n");
+ rv = SECFailure;
+ goto cleanup;
+ }
+
+ data->len = SECKEY_PublicKeyStrength(pubKey);
+ data->data = (unsigned char*)PORT_ZAlloc((data->len)*sizeof(unsigned int));
+
+ if (!data->data) {
+ PR_fprintf(PR_STDERR, "Error while allocating memory\n");
+ rv = SECFailure;
+ goto cleanup;
+ }
+
+ rv = PK11_PubWrapSymKey(CKM_RSA_PKCS, pubKey, key, data);
+ if (rv != SECSuccess) {
+ rv = SECFailure;
+ } else {
+ *wrappedKey = data;
+ return SECSuccess;
+ }
+
+ cleanup:
+ if (data) {
+ SECITEM_FreeItem(data, PR_TRUE);
+ }
+ return rv;
+ }
+
+ /*
+ * Generate a Symmetric Key
+ */
+ PK11SymKey *
+ GenerateSYMKey(PK11SlotInfo *slot, CK_MECHANISM_TYPE mechanism,
+ int keySize, SECItem *keyID, secuPWData *pwdata)
+ {
+ SECStatus rv;
+ PK11SymKey *key;
+
+ /* Generate the symmetric key */
+ key = PK11_TokenKeyGen(slot, mechanism,
+ NULL, keySize, keyID, PR_FALSE, pwdata);
+
+ if (!key) {
+ PR_fprintf(PR_STDERR, "Symmetric Key Generation Failed \n");
+ }
+
+ return key;
+ }
+
+ /*
+ * MacInit
+ */
+ SECStatus
+ MacInit(PK11Context *ctx)
+ {
+ SECStatus rv = PK11_DigestBegin(ctx);
+ if (rv != SECSuccess) {
+ PR_fprintf(PR_STDERR, "Compute MAC Failed : PK11_DigestBegin()\n");
+ }
+ return rv;
+ }
+
+ /*
+ * MacUpdate
+ */
+ SECStatus
+ MacUpdate(PK11Context *ctx,
+ unsigned char *msg, unsigned int msgLen)
+ {
+ SECStatus rv = PK11_DigestOp(ctx, msg, msgLen);
+ if (rv != SECSuccess) {
+ PR_fprintf(PR_STDERR, "Compute MAC Failed : DigestOp()\n");
+ }
+ return rv;
+ }
+
+ /*
+ * Finalize MACing
+ */
+ SECStatus
+ MacFinal(PK11Context *ctx,
+ unsigned char *mac, unsigned int *macLen, unsigned int maxLen)
+ {
+ SECStatus rv = PK11_DigestFinal(ctx, mac, macLen, maxLen);
+ if (rv != SECSuccess) {
+ PR_fprintf(PR_STDERR, "Compute MAC Failed : PK11_DigestFinal()\n");
+ }
+ return SECSuccess;
+ }
+
+ /*
+ * Compute Mac
+ */
+ SECStatus
+ ComputeMac(PK11Context *ctxmac,
+ unsigned char *ptext, unsigned int ptextLen,
+ unsigned char *mac, unsigned int *macLen,
+ unsigned int maxLen)
+ {
+ SECStatus rv = MacInit(ctxmac);
+ if (rv != SECSuccess) return rv;
+ rv = MacUpdate(ctxmac, ptext, ptextLen);
+ if (rv != SECSuccess) return rv;
+ rv = MacFinal(ctxmac, mac, macLen, maxLen);
+ return rv;
+ }
+
+ /*
+ * WriteToHeaderFile
+ */
+ 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 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);
+ PrintAsAscii(outFile, buf, len);
+ PR_fprintf(outFile, "%s\n\n", trailer);
+ return SECSuccess;
+ }
+
+ /*
+ * Initialize for encryption or decryption - common code
+ */
+ PK11Context *
+ CryptInit(PK11SymKey *key,
+ unsigned char *iv, unsigned int ivLen,
+ CK_MECHANISM_TYPE type, CK_ATTRIBUTE_TYPE operation)
+ {
+ SECItem ivItem = { siBuffer, iv, ivLen };
+ PK11Context *ctx = NULL;
+
+ SECItem *secParam = PK11_ParamFromIV(type, &ivItem);
+ if (secParam == NULL) {
+ PR_fprintf(PR_STDERR, "Crypt Failed : secParam NULL\n");
+ return NULL;
+ }
+ ctx = PK11_CreateContextBySymKey(type, operation, key, secParam);
+ if (ctx == NULL) {
+ PR_fprintf(PR_STDERR, "Crypt Failed : can't create a context\n");
+ goto cleanup;
+
+ }
+ cleanup:
+ if (secParam) {
+ SECITEM_FreeItem(secParam, PR_TRUE);
+ }
+ return ctx;
+ }
+
+ /*
+ * Common encryption and decryption code
+ */
+ SECStatus
+ Crypt(PK11Context *ctx,
+ unsigned char *out, unsigned int *outLen, unsigned int maxOut,
+ unsigned char *in, unsigned int inLen)
+ {
+ SECStatus rv;
+
+ rv = PK11_CipherOp(ctx, out, outLen, maxOut, in, inLen);
+ if (rv != SECSuccess) {
+ PR_fprintf(PR_STDERR, "Crypt Failed : PK11_CipherOp returned %d\n", rv);
+ goto cleanup;
+ }
+
+ cleanup:
+ if (rv != SECSuccess) {
+ return rv;
+ }
+ return SECSuccess;
+ }
+
+ /*
+ * Decrypt
+ */
+ SECStatus
+ Decrypt(PK11Context *ctx,
+ unsigned char *out, unsigned int *outLen, unsigned int maxout,
+ unsigned char *in, unsigned int inLen)
+ {
+ return Crypt(ctx, out, outLen, maxout, in, inLen);
+ }
+
+ /*
+ * Encrypt
+ */
+ SECStatus
+ Encrypt(PK11Context* ctx,
+ unsigned char *out, unsigned int *outLen, unsigned int maxout,
+ unsigned char *in, unsigned int inLen)
+ {
+ return Crypt(ctx, out, outLen, maxout, in, inLen);
+ }
+
+ /*
+ * EncryptInit
+ */
+ PK11Context *
+ EncryptInit(PK11SymKey *ek, unsigned char *iv, unsigned int ivLen,
+ CK_MECHANISM_TYPE type)
+ {
+ return CryptInit(ek, iv, ivLen, type, CKA_ENCRYPT);
+ }
+
+ /*
+ * DecryptInit
+ */
+ PK11Context *
+ DecryptInit(PK11SymKey *dk, unsigned char *iv, unsigned int ivLen,
+ CK_MECHANISM_TYPE type)
+ {
+ return CryptInit(dk, iv, ivLen, type, CKA_DECRYPT);
+ }
+
+ /*
+ * Read cryptographic parameters from the header file
+ */
+ SECStatus
+ ReadFromHeaderFile(const char *fileName, HeaderType type,
+ SECItem *item, PRBool isHexData)
+ {
+ SECStatus rv;
+ SECItem filedata;
+ SECItem outbuf;
+ unsigned char *nonbody;
+ unsigned char *body;
+ char *header;
+ char *trailer;
+ PRFileDesc *file = NULL;
+
+ outbuf.type = siBuffer;
+ file = PR_Open(fileName, PR_RDONLY, 0);
+ if (!file) {
+ PR_fprintf(PR_STDERR, "Failed to open %s\n", fileName);
+ return SECFailure;
+ }
+ 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;
+ default:
+ PR_Close(file);
+ return SECFailure;
+ }
+
+ 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 */
+ char *trail = NULL;
+ 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);
+ return SECFailure;
+ }
+ } else {
+ /* headers didn't exist */
+ 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);
+ return SECFailure;
+ }
+ }
+ }
+
+ cleanup:
+ PR_Close(file);
+ ATOB_ConvertAsciiToItem(item, body);
+ return SECSuccess;
+ }
+
+ /*
+ * Generate the private key
+ */
+ SECKEYPrivateKey *
+ GeneratePrivateKey(KeyType keytype, PK11SlotInfo *slot, int size,
+ int publicExponent, const char *noiseFileName,
+ 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;
+ }
+
+ /*
+ * Extract the public key request from CSR
+ */
+ SECKEYPublicKey *
+ ExtractPublicKeyFromCertRequest(const char *inFileName, PRBool ascii)
+ {
+ CERTSignedData signedData;
+ SECItem reqDER;
+ CERTCertificateRequest *certReq = NULL;
+ SECStatus rv = SECSuccess;
+ PRArenaPool *arena = NULL;
+ SECKEYPublicKey *publicKey = 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 */);
+ publicKey = SECKEY_ExtractPublicKey(&certReq->subjectPublicKeyInfo);
+
+ cleanup:
+ if (reqDER.data) {
+ SECITEM_FreeItem(&reqDER, PR_FALSE);
+ }
+ if (arena) {
+ PORT_FreeArena(arena, PR_FALSE);
+ }
+ return publicKey;
+ }
+
+ /*
+ * Get the private key corresponding to public key
+ */
+ SECKEYPrivateKey *
+ GetRSAPrivateKey(PK11SlotInfo *slot,
+ secuPWData *pwdata,
+ SECKEYPublicKey *pubKey)
+ {
+ SECKEYPrivateKey *privKey = NULL;
+ SECItem *cka_id;
+
+ if (slot == NULL) {
+ fprintf(stderr, "Empty Slot\n");
+ goto cleanup;
+ }
+ if (PK11_Authenticate(slot, PR_TRUE, pwdata) != SECSuccess) {
+ fprintf(stderr, "could not authenticate to token %s.",
+ PK11_GetTokenName(slot));
+ goto cleanup;
+ }
+ cka_id = &pubKey->u.rsa.modulus;
+ cka_id = PK11_MakeIDFromPubKey(cka_id);
+ privKey = PK11_FindKeyByKeyID(slot, cka_id, pwdata);
+ cleanup:
+ return privKey;
+ }
+
+ /*
+ * Generate the certificate request with subject
+ */
+ static SECStatus
+ CertReq(SECKEYPrivateKey *privk, SECKEYPublicKey *pubk, KeyType keyType,
+ SECOidTag hashAlgTag, CERTName *subject, PRBool ascii,
+ const char *certReqFileName)
+ {
+ CERTSubjectPublicKeyInfo *spki = NULL;
+ CERTCertificateRequest *cr = NULL;
+ SECItem *encoding = NULL;
+ SECOidTag signAlgTag;
+ SECItem result;
+ SECStatus rv = SECSuccess;
+ PRInt32 numBytes;
+ void *extHandle;
+ PRArenaPool *arena = NULL;
+ PRFileDesc *outFile = NULL;
+
+ /* 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);
+ if (obuf) {
+ PORT_Free(obuf);
+ }
+ } 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 (spki) {
+ SECKEY_DestroySubjectPublicKeyInfo(spki);
+ }
+ if (cr) {
+ CERT_DestroyCertificateRequest (cr);
+ }
+ if (arena) {
+ PORT_FreeArena(arena, PR_FALSE);
+ }
+ if (outFile) {
+ PR_Close(outFile);
+ }
+ return rv;
+ }
+
+ /*
+ * Mac and Encrypt the input file content
+ */
+ SECStatus
+ EncryptAndMac(PRFileDesc *inFile,
+ PRFileDesc *headerFile,
+ PRFileDesc *encFile,
+ PK11SymKey *ek,
+ PK11SymKey *mk,
+ unsigned char *iv, unsigned int ivLen,
+ PRBool ascii)
+ {
+ SECStatus rv;
+ unsigned char ptext[BLOCKSIZE];
+ unsigned int ptextLen;
+ unsigned char mac[DIGESTSIZE];
+ unsigned int macLen;
+ unsigned int nwritten;
+ unsigned char encbuf[BLOCKSIZE];
+ unsigned int encbufLen;
+ SECItem noParams = { siBuffer, NULL, 0 };
+ PK11Context *ctxmac = NULL;
+ PK11Context *ctxenc = NULL;
+ unsigned int pad[1];
+ SECItem padItem;
+ unsigned int paddingLength = 0;
+
+ static unsigned int firstTime = 1;
+ int j;
+
+ ctxmac = PK11_CreateContextBySymKey(CKM_MD5_HMAC, CKA_SIGN, mk, &noParams);
+ if (ctxmac == NULL) {
+ PR_fprintf(PR_STDERR, "Can't create MAC context\n");
+ rv = SECFailure;
+ goto cleanup;
+ }
+ rv = MacInit(ctxmac);
+ if (rv != SECSuccess) {
+ goto cleanup;
+ }
+
+ ctxenc = EncryptInit(ek, iv, ivLen, CKM_AES_CBC);
+
+ /* read a buffer of plaintext from input file */
+ while ((ptextLen = PR_Read(inFile, ptext, sizeof(ptext))) > 0) {
+ /* Encrypt using it using CBC, using previously created IV */
+ if (ptextLen != BLOCKSIZE) {
+ paddingLength = BLOCKSIZE - ptextLen;
+ for ( j=0; j < paddingLength; j++) {
+ ptext[ptextLen+j] = (unsigned char)paddingLength;
+ }
+ ptextLen = BLOCKSIZE;
+ }
+ rv = Encrypt(ctxenc,
+ encbuf, &encbufLen, sizeof(encbuf),
+ ptext, ptextLen);
+ if (rv != SECSuccess) {
+ PR_fprintf(PR_STDERR, "Encrypt Failure\n");
+ goto cleanup;
+ }
+
+ /* save the last block of ciphertext as the next IV */
+ iv = encbuf;
+ ivLen = encbufLen;
+
+ /* write the cipher text to intermediate file */
+ nwritten = PR_Write(encFile, encbuf, encbufLen);
+ /*PR_Assert(nwritten == encbufLen);*/
+
+ rv = MacUpdate(ctxmac, ptext, ptextLen);
+ if (rv != SECSuccess)
+ goto cleanup;
+ }
+
+ rv = MacFinal(ctxmac, mac, &macLen, DIGESTSIZE);
+ if (rv != SECSuccess) {
+ PR_fprintf(PR_STDERR, "MacFinal Failure\n");
+ goto cleanup;
+ }
+ if (macLen == 0) {
+ PR_fprintf(PR_STDERR, "Bad MAC length\n");
+ rv = SECFailure;
+ goto cleanup;
+ }
+ WriteToHeaderFile(mac, macLen, MAC, headerFile);
+ if (rv != SECSuccess) {
+ PR_fprintf(PR_STDERR, "Write MAC Failure\n");
+ goto cleanup;
+ }
+
+ pad[0] = paddingLength;
+ padItem.type = siBuffer;
+ padItem.data = (unsigned char *)pad;
+ padItem.len = sizeof(pad[0]);
+
+ WriteToHeaderFile(padItem.data, padItem.len, PAD, headerFile);
+ if (rv != SECSuccess) {
+ PR_fprintf(PR_STDERR, "Write PAD Failure\n");
+ goto cleanup;
+ }
+
+ rv = SECSuccess;
+
+ cleanup:
+ if (ctxmac != NULL) {
+ PK11_DestroyContext(ctxmac, PR_TRUE);
+ }
+ if (ctxenc != NULL) {
+ PK11_DestroyContext(ctxenc, PR_TRUE);
+ }
+
+ return rv;
+ }
+
+ /*
+ * Decrypt and Verify MAC
+ */
+ SECStatus
+ DecryptAndVerifyMac(PRFileDesc *outFile,
+ PRFileDesc *inFile, unsigned int inFileLength,
+ SECItem *cItem, SECItem *macItem,
+ PK11SymKey* ek, PK11SymKey* mk, SECItem *ivItem, SECItem *padItem)
+ {
+ SECStatus rv;
+ unsigned char decbuf[64];
+ unsigned int decbufLen;
+
+ unsigned char ptext[BLOCKSIZE];
+ unsigned int ptextLen = 0;
+ unsigned char ctext[64];
+ unsigned int ctextLen;
+ unsigned char newmac[DIGESTSIZE];
+ unsigned int newmacLen = 0;
+ unsigned int newptextLen = 0;
+ unsigned int count = 0;
+ unsigned int temp = 0;
+ unsigned int blockNumber = 0;
+ SECItem noParams = { siBuffer, NULL, 0 };
+ PK11Context *ctxmac = NULL;
+ PK11Context *ctxenc = NULL;
+
+ unsigned char iv[BLOCKSIZE];
+ unsigned int ivLen = ivItem->len;
+ unsigned int paddingLength;
+ int j;
+
+ memcpy(iv, ivItem->data, ivItem->len);
+ paddingLength = (unsigned int)padItem->data[0];
+
+ ctxmac = PK11_CreateContextBySymKey(CKM_MD5_HMAC, CKA_SIGN, mk, &noParams);
+ if (ctxmac == NULL) {
+ PR_fprintf(PR_STDERR, "Can't create MAC context\n");
+ rv = SECFailure;
+ goto cleanup;
+ }
+
+ rv = MacInit(ctxmac);
+ if (rv != SECSuccess) goto cleanup;
+
+ ctxenc = DecryptInit(ek, iv, ivLen, CKM_AES_CBC);
+
+ while ((ctextLen = PR_Read(inFile, ctext, sizeof(ctext))) > 0) {
+
+ count += ctextLen;
+
+ /* decrypt cipher text buffer using CBC and IV */
+
+ rv = Decrypt(ctxenc, decbuf, &decbufLen, sizeof(decbuf),
+ ctext, ctextLen);
+
+ if (rv != SECSuccess) {
+ PR_fprintf(PR_STDERR, "Decrypt Failure\n");
+ goto cleanup;
+ }
+
+ if (decbufLen == 0) break;
+
+ rv = MacUpdate(ctxmac, decbuf, decbufLen);
+ if (rv != SECSuccess) { goto cleanup; }
+ 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;
+ }
+
+ blockNumber++;
+ }
+
+ if (rv != SECSuccess) { goto cleanup; }
+
+ rv = MacFinal(ctxmac, newmac, &newmacLen, sizeof(newmac));
+ if (rv != SECSuccess) { goto cleanup; }
+
+ if (PORT_Memcmp(macItem->data, newmac, newmacLen) == 0) {
+ rv = SECSuccess;
+ } else {
+ PR_fprintf(PR_STDERR, "Check MAC : Failure\n");
+ PR_fprintf(PR_STDERR, "Extracted : ");
+ PrintAsAscii(PR_STDERR, macItem->data, macItem->len);
+ PR_fprintf(PR_STDERR, "Computed : ");
+ PrintAsAscii(PR_STDERR, newmac, newmacLen);
+ rv = SECFailure;
+ }
+ cleanup:
+ if (ctxmac) {
+ PK11_DestroyContext(ctxmac, PR_TRUE);
+ }
+ if (ctxenc) {
+ PK11_DestroyContext(ctxenc, PR_TRUE);
+ }
+
+ return rv;
+ }
+
+ /*
+ * Open intermediate file, read in IV, wrapped encryption key,
+ * wrapped MAC key, MAC, PAD and public key from header file
+ */
+ SECStatus
+ GetDataFromHeader(const char *headerFileName,
+ SECItem *ivItem,
+ SECItem *wrappedEncKeyItem,
+ SECItem *wrappedMacKeyItem,
+ SECItem *macItem,
+ SECItem *padItem,
+ SECKEYPublicKey **pubKey)
+ {
+ SECStatus rv = SECSuccess;
+ CERTSubjectPublicKeyInfo *keyInfo = NULL;
+ SECItem pubKeyData;
+
+ /* Read in the IV into item from the header file */
+ rv = ReadFromHeaderFile(headerFileName, IV, ivItem, PR_TRUE);
+ if (rv != SECSuccess) {
+ PR_fprintf(PR_STDERR, "Could not retrieve IV from cipher file\n");
+ goto cleanup;
+ }
+
+ rv = ReadFromHeaderFile(headerFileName, SYMKEY, wrappedEncKeyItem, PR_TRUE);
+ if (rv != SECSuccess) {
+ PR_fprintf(PR_STDERR,
+ "Could not retrieve wrapped AES key from header file\n");
+ goto cleanup;
+ }
+ /* Read in the MAC key into item from the header file */
+ rv = ReadFromHeaderFile(headerFileName, MACKEY, wrappedMacKeyItem, PR_TRUE);
+ if (rv != SECSuccess) {
+ PR_fprintf(PR_STDERR,
+ "Could not retrieve wrapped MAC key from header file\n");
+ goto cleanup;
+ }
+
+ /* Get the public key from header file */
+ rv = ReadFromHeaderFile(headerFileName, PUBKEY, &pubKeyData, PR_TRUE);
+ if (rv != SECSuccess) {
+ PR_fprintf(PR_STDERR,
+ "Could not retrieve public key from header file\n");
+ goto cleanup;
+ }
+ keyInfo = SECKEY_DecodeDERSubjectPublicKeyInfo(&pubKeyData);
+ if (!keyInfo) {
+ PR_fprintf(PR_STDERR, "Could not decode public key\n");
+ rv = SECFailure;
+ goto cleanup;
+ }
+ *pubKey = SECKEY_ExtractPublicKey(keyInfo);
+ if (*pubKey == NULL) {
+ PR_fprintf(PR_STDERR, "Error while getting RSA public key\n");
+ rv = SECFailure;
+ goto cleanup;
+ }
+ /* Read in the Mac into item from the header file */
+ rv = ReadFromHeaderFile(headerFileName, MAC, macItem, PR_TRUE);
+ if (rv != SECSuccess) {
+ PR_fprintf(PR_STDERR,
+ "Could not retrieve MAC from cipher file\n");
+ goto cleanup;
+ }
+ if (macItem->data == NULL) {
+ PR_fprintf(PR_STDERR, "MAC has NULL data\n");
+ rv = SECFailure;
+ goto cleanup;
+ }
+ if (macItem->len == 0) {
+ PR_fprintf(PR_STDERR, "MAC has data has 0 length\n");
+ rv = SECFailure;
+ goto cleanup;
+ }
+
+ /* Read in the PAD into item from the 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;
+ }
+
+ cleanup:
+ return rv;
+ }
+
+
+ /*
+ * DecryptFile
+ */
+ SECStatus
+ DecryptFile(PK11SlotInfo *slot,
+ const char *outFileName,
+ const char *headerFileName,
+ char *encryptedFileName,
+ secuPWData *pwdata,
+ PRBool ascii)
+ {
+ /*
+ * The DB is open read only and we have authenticated to it
+ * open input file, read in header, get IV and wrapped keys and
+ * public key
+ * Unwrap the wrapped keys
+ * loop until EOF(input):
+ * read a buffer of ciphertext from input file,
+ * Save last block of ciphertext
+ * decrypt ciphertext buffer using CBC and IV,
+ * compute and check MAC, then remove MAC from plaintext
+ * replace IV with saved last block of ciphertext
+ * write the plain text to output file
+ * close files
+ * report success
+ */
+
+ SECStatus rv;
+ SECItem ivItem;
+ SECItem wrappedEncKeyItem;
+ SECItem wrappedMacKeyItem;
+ SECItem cipherItem;
+ SECItem macItem;
+ SECItem padItem;
+ SECKEYPublicKey *pubKey = NULL;
+ PK11SymKey *encKey = NULL;
+ PK11SymKey *macKey = NULL;
+ SECKEYPrivateKey *privKey = NULL;
+ PRFileDesc *outFile = NULL;
+ PRFileDesc *inFile = NULL;
+ unsigned int inFileLength = 0;
+
+ /* open intermediate file, read in header, get IV, public key and
+ * CKA_IDs of two keys from it
+ */
+ rv = GetDataFromHeader(headerFileName,
+ &ivItem,
+ &wrappedEncKeyItem,
+ &wrappedMacKeyItem,
+ &macItem,
+ &padItem,
+ &pubKey);
+ if (rv != SECSuccess) {
+ goto cleanup;
+ }
+
+ /* find private key from the DB token using public key */
+ privKey = GetRSAPrivateKey(slot, pwdata, pubKey);
+ if (privKey == NULL) {
+ PR_fprintf(PR_STDERR, "Can't find private key\n");
+ rv = SECFailure;
+ goto cleanup;
+ }
+
+ encKey = PK11_PubUnwrapSymKey(privKey, &wrappedEncKeyItem,
+ CKM_AES_CBC, CKA_ENCRYPT, 0);
+ if (encKey == NULL) {
+ PR_fprintf(PR_STDERR, "Can't unwrap the encryption key\n");
+ rv = SECFailure;
+ goto cleanup;
+ }
+
+ /* CKM_MD5_HMAC or CKM_EXTRACT_KEY_FROM_KEY */
+ macKey = PK11_PubUnwrapSymKey(privKey, &wrappedMacKeyItem,
+ CKM_MD5_HMAC, CKA_SIGN, 160/8);
+ if (macKey == NULL) {
+ PR_fprintf(PR_STDERR, "Can't unwrap the Mac key\n");
+ rv = SECFailure;
+ goto cleanup;
+ }
+
+ /* Open the input file. */
+ inFile = PR_Open(encryptedFileName, PR_RDONLY , 0);
+ if (!inFile) {
+ PR_fprintf(PR_STDERR,
+ "Unable to open \"%s\" for writing.\n",
+ encryptedFileName);
+ return SECFailure;
+ }
+ /* Open the output file. */
+ 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);
+ return SECFailure;
+ }
+ inFileLength = FileSize(encryptedFileName);
+
+ if (rv == SECSuccess) {
+ /* Decrypt and Remove Mac */
+ rv = DecryptAndVerifyMac(outFile, inFile, inFileLength,
+ &cipherItem, &macItem, encKey, macKey, &ivItem, &padItem);
+ if (rv != SECSuccess) {
+ PR_fprintf(PR_STDERR, "Failed while decrypting and removing MAC\n");
+ }
+ }
+
+ cleanup:
+ if (encKey) {
+ PK11_FreeSymKey(encKey);
+ }
+ if (macKey) {
+ PK11_FreeSymKey(macKey);
+ }
+ if (privKey) {
+ SECKEY_DestroyPrivateKey(privKey);
+ }
+ if (pubKey) {
+ SECKEY_DestroyPublicKey(pubKey);
+ }
+ return rv;
+ }
+
+ /*
+ * EncryptFile
+ */
+ SECStatus
+ EncryptFile(PK11SlotInfo *slot,
+ const char *inFileName,
+ const char *certReqFileName,
+ const char *headerFileName,
+ const char *encryptedFileName,
+ const char *noiseFileName,
+ secuPWData *pwdata,
+ PRBool ascii)
+ {
+ /*
+ * The DB is open for read/write and we have authenticated to it.
+ * Read public key from certificate request
+ * generate a symmetric AES key as a session object.
+ * generate a second key to use for MACing, also a session object.
+ * generate a random value to use as IV for AES CBC
+ * open an input file and an output file,
+ * Wrap the symmetric and MAC keys using public key
+ * write a header to the output that identifies the two wrapped keys
+ * and public key
+ * loop until EOF(input)
+ * read a buffer of plaintext from input file,
+ * MAC it, append the MAC to the plaintext
+ * encrypt it using CBC, using previously created IV,
+ * store the last block of ciphertext as the new IV,
+ * write the cipher text to intermediate file
+ * close files
+ * report success
+ */
+ SECStatus rv;
+ SECKEYPublicKey *pubKey = NULL;
+ SECItem *pubKeyData = NULL;
+ PRFileDesc *inFile = NULL;
+ PRFileDesc *headerFile = NULL;
+ PRFileDesc *encFile = NULL;
+
+ unsigned char *encKeyId = (unsigned char *) "Encrypt Key";
+ unsigned char *macKeyId = (unsigned char *) "MAC Key";
+ SECItem encKeyID = { siAsciiString, encKeyId, PL_strlen(encKeyId) };
+ SECItem macKeyID = { siAsciiString, macKeyId, PL_strlen(macKeyId) };
+
+ unsigned char iv[BLOCKSIZE];
+ SECItem ivItem;
+ PK11SymKey *encKey = NULL;
+ PK11SymKey *macKey = NULL;
+ SECItem *wrappedEncKey = NULL;
+ SECItem *wrappedMacKey = NULL;
+ unsigned char c;
+
+ pubKey = ExtractPublicKeyFromCertRequest(certReqFileName, ascii);
+ if (pubKey == NULL) {
+ PR_fprintf(PR_STDERR, "Error while getting RSA public key\n");
+ rv = SECFailure;
+ goto cleanup;
+ }
+ /* generate a symmetric AES key as a token object. */
+ encKey = GenerateSYMKey(slot, CKM_AES_KEY_GEN, 128/8, &encKeyID, pwdata);
+ if (encKey == NULL) {
+ PR_fprintf(PR_STDERR, "GenerateSYMKey for AES returned NULL.\n");
+ rv = SECFailure;
+ goto cleanup;
+ }
+
+ /* generate a second key to use for MACing, also a token object. */
+ macKey = GenerateSYMKey(slot, CKM_GENERIC_SECRET_KEY_GEN, 160/8, &macKeyID, pwdata);
+ if (macKey == NULL) {
+ PR_fprintf(PR_STDERR, "GenerateSYMKey for MACing returned NULL.\n");
+ rv = SECFailure;
+ goto cleanup;
+ }
+
+ /* Wrap encrypt key */
+ rv = WrapKey(encKey, pubKey, &wrappedEncKey);
+ if (rv != SECSuccess) {
+ PR_fprintf(PR_STDERR, "Error while wrapping encrypt key\n");
+ goto cleanup;
+ }
+
+ /* Wrap Mac key */
+ rv = WrapKey(macKey, pubKey, &wrappedMacKey);
+ if (rv != SECSuccess) {
+ PR_fprintf(PR_STDERR, "Error while wrapping Mac key\n");
+ goto cleanup;
+ }
+
+ if (noiseFileName) {
+ rv = SeedFromNoiseFile(noiseFileName);
+ if (rv != SECSuccess) {
+ PORT_SetError(PR_END_OF_FILE_ERROR);
+ return SECFailure;
+ }
+ rv = PK11_GenerateRandom(iv, BLOCKSIZE);
+ if (rv != SECSuccess) {
+ goto cleanup;
+ }
+
+ } else {
+ /* generate a random value to use as IV for AES CBC */
+ GenerateRandom(iv, BLOCKSIZE);
+ }
+
+ headerFile = PR_Open(headerFileName,
+ PR_CREATE_FILE | PR_TRUNCATE | PR_RDWR, 00660);
+ if (!headerFile) {
+ PR_fprintf(PR_STDERR,
+ "Unable to open \"%s\" for writing.\n",
+ headerFileName);
+ return SECFailure;
+ }
+ 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);
+ return SECFailure;
+ }
+ /* write to a header file the IV and the CKA_IDs
+ * identifying the two keys
+ */
+ ivItem.type = siBuffer;
+ ivItem.data = iv;
+ ivItem.len = BLOCKSIZE;
+
+ rv = WriteToHeaderFile(iv, BLOCKSIZE, IV, headerFile);
+ if (rv != SECSuccess) {
+ PR_fprintf(PR_STDERR, "Error writing IV to cipher file - %s\n",
+ headerFileName);
+ goto cleanup;
+ }
+
+ rv = WriteToHeaderFile(wrappedEncKey->data, wrappedEncKey->len, SYMKEY, headerFile);
+ if (rv != SECSuccess) {
+ PR_fprintf(PR_STDERR, "Error writing wrapped AES key to cipher file - %s\n",
+ encryptedFileName);
+ goto cleanup;
+ }
+ rv = WriteToHeaderFile(wrappedMacKey->data, wrappedMacKey->len, MACKEY, headerFile);
+ if (rv != SECSuccess) {
+ PR_fprintf(PR_STDERR, "Error writing wrapped MAC key to cipher file - %s\n",
+ headerFileName);
+ goto cleanup;
+ }
+
+ pubKeyData = SECKEY_EncodeDERSubjectPublicKeyInfo(pubKey);
+ rv = WriteToHeaderFile(pubKeyData->data, pubKeyData->len, PUBKEY, headerFile);
+ if (rv != SECSuccess) {
+ PR_fprintf(PR_STDERR, "Error writing wrapped AES key to cipher file - %s\n",
+ headerFileName);
+ goto cleanup;
+ }
+
+ /* 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);
+ return SECFailure;
+ }
+
+ /* Macing and Encryption */
+ if (rv == SECSuccess) {
+ rv = EncryptAndMac(inFile, headerFile, encFile,
+ encKey, macKey, ivItem.data, ivItem.len, ascii);
+ if (rv != SECSuccess) {
+ PR_fprintf(PR_STDERR, "Failed : Macing and Encryption\n");
+ goto cleanup;
+ }
+ }
+
+ cleanup:
+ if (inFile) {
+ PR_Close(inFile);
+ }
+ if (headerFile) {
+ PR_Close(headerFile);
+ }
+ if (encFile) {
+ PR_Close(encFile);
+ }
+ if (encKey) {
+ PK11_FreeSymKey(encKey);
+ }
+ if (macKey) {
+ PK11_FreeSymKey(macKey);
+ }
+ if (wrappedEncKey) {
+ SECITEM_FreeItem(wrappedEncKey, PR_TRUE);
+ }
+ if (wrappedMacKey) {
+ SECITEM_FreeItem(wrappedMacKey, PR_TRUE);
+ }
+ if (pubKey) {
+ SECKEY_DestroyPublicKey(pubKey);
+ }
+ if (pubKeyData) {
+ SECITEM_FreeItem(pubKeyData, PR_TRUE);
+ }
+ return rv;
+ }
+
+ /*
+ * Create certificate request with subject
+ */
+ SECStatus CreateCertificateRequest(PK11SlotInfo *slot,
+ const char *dbdir,
+ secuPWData *pwdata,
+ CERTName *subject,
+ const 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:
+ if (privkey) {
+ SECKEY_DestroyPrivateKey(privkey);
+ }
+ if (pubkey) {
+ SECKEY_DestroyPublicKey(pubkey);
+ }
+ return rv;
+ }
+
+ /*
+ * This example illustrates basic encryption/decryption and MACing
+ * Generates the RSA key pair as token object and outputs public key as cert request.
+ * Generates the encryption/mac keys as session objects.
+ * Encrypts/MACs the input file using encryption keys and outputs the encrypted
+ * contents into intermediate header file.
+ * Extracts the public key from cert request file and Wraps the encryption keys using
+ * RSA public key and outputs wrapped keys and public key into intermediate header file.
+ * Reads the intermediate headerfile for wrapped keys,RSA public key and encrypted
+ * contents and decrypts into output file.
+ *
+ * How this sample is different from sample 4 ?
+ *
+ * 1. Generate same keys as sample 4, outputs public key as cert request.
+ * 2. Like sample 4, except that it reads in public key from cert request file instead
+ * of looking it up by label name, and writes public key into header instead of a
+ * label name. Rest is the same.
+ * 3. Like sample 4, except that it reads in RSA public key, and then finds matching
+ * private key (by key ID). Rest is the same.
+ */
+ int
+ main(int argc, char **argv)
+ {
+ SECStatus rv;
+ SECStatus rvShutdown;
+ PLOptState *optstate;
+ PLOptStatus status;
+ char headerFileName[50];
+ char encryptedFileName[50];
+ PK11SlotInfo *slot = NULL;
+ PRBool ascii = PR_FALSE;
+ CommandType cmd = UNKNOWN;
+ PRFileDesc *inFile = NULL;
+ PRFileDesc *outFile = NULL;
+ char *subjectStr = NULL;
+ CERTName *subject = NULL;
+ const char *dbdir = NULL;
+ const char *inFileName = NULL;
+ const char *outFileName = NULL;
+ const char *certReqFileName = NULL;
+ const char *noiseFileName = NULL;
+ secuPWData pwdata = { PW_NONE, 0 };
+
+ char * progName = strrchr(argv[0], '/');
+ progName = progName ? progName + 1 : argv[0];
+
+ /* Parse command line arguments */
+ optstate = PL_CreateOptState(argc, argv, "c:d:i:o:f:p:z:a:s:r:");
+ while ((status = PL_GetNextOpt(optstate)) == PL_OPT_OK) {
+ switch (optstate->option) {
+ case 'a':
+ ascii = PR_TRUE;
+ break;
+ case 'c':
+ cmd = option2Command(optstate->value);
+ 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 'o':
+ outFileName = strdup(optstate->value);
+ break;
+ case 'r':
+ certReqFileName = strdup(optstate->value);
+ break;
+ case 's':
+ subjectStr = strdup(optstate->value);
+ subject = CERT_AsciiToName(subjectStr);
+ break;
+ case 'z':
+ noiseFileName = strdup(optstate->value);
+ break;
+ default:
+ Usage(progName);
+ break;
+ }
+ }
+ PL_DestroyOptState(optstate);
+
+ if (cmd == UNKNOWN || !dbdir) {
+ Usage(progName);
+ }
+
+ /* For intermediate header file, choose filename as inputfile name
+ with extension ".header" */
+ strcpy(headerFileName, progName);
+ strcat(headerFileName, ".header");
+
+ /* For intermediate encrypted file, choose filename as inputfile name
+ with extension ".enc" */
+ strcpy(encryptedFileName, progName);
+ strcat(encryptedFileName, ".enc");
+ PR_Init(PR_USER_THREAD, PR_PRIORITY_NORMAL, 0);
+
+ /* Open DB for read/write and authenticate to it. */
+ rv = NSS_InitReadWrite(dbdir);
+ if (rv != SECSuccess) {
+ PR_fprintf(PR_STDERR, "NSS_InitReadWrite Failed\n");
+ goto cleanup;
+ }
+
+ PK11_SetPasswordFunc(GetModulePassword);
+ slot = PK11_GetInternalKeySlot();
+ 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 GEN_CSR:
+
+ /* Validate command for Generate CSR */
+ if (!certReqFileName || !subject) {
+ Usage(progName);
+ }
+ /*
+ * Generate the cert request and save it
+ * in a file so public key can be retrieved later to wrap the symmetric key
+ */
+ rv = CreateCertificateRequest(slot, dbdir, &pwdata, subject, certReqFileName, ascii);
+ if (rv != SECSuccess) {
+ PR_fprintf(PR_STDERR, "Create Certificate Request: Failed\n");
+ goto cleanup;
+ }
+ break;
+ case ENCRYPT:
+ /* Validate command for Encrypt */
+ if (!certReqFileName && !inFileName) {
+ Usage(progName);
+ }
+
+ /*
+ * Read cert request from a file and extract public key
+ * Generates an AES encryption key, session object
+ * Generates a MAC key, session object
+ * Wraps each of those keys with RSA public key
+ * Write wrapped keys and public key into intermediate header file
+ * Encryption and MACing loop
+ * Destroy session keys
+ * Close files
+ */
+ rv = EncryptFile(slot, inFileName, certReqFileName,
+ headerFileName, encryptedFileName,
+ noiseFileName, &pwdata, ascii);
+ if (rv != SECSuccess) {
+ PR_fprintf(PR_STDERR, "EncryptFile : Failed\n");
+ return SECFailure;
+ }
+ break;
+ case DECRYPT:
+ /* Validate command for Decrypt */
+ if (!inFileName && !outFileName) {
+ Usage(progName);
+ }
+ /*
+ * Reads intermediate header including public key and wrapped keys
+ * Finds RSA private key corresponding to the public key
+ * unwraps two keys, creating session key objects
+ * Decryption and MAC checking loop to write to output file
+ * Destroy session keys
+ * CLose files
+ */
+ rv = DecryptFile(slot,
+ outFileName, headerFileName,
+ encryptedFileName, &pwdata, ascii);
+ if (rv != SECSuccess) {
+ PR_fprintf(PR_STDERR, "DecryptFile : Failed\n");
+ return SECFailure;
+ }
+ break;
+ }
+
+ cleanup:
+ if (slot) {
+ PK11_FreeSlot(slot);
+ }
+ rvShutdown = NSS_Shutdown();
+ if (rvShutdown != SECSuccess) {
+ PR_fprintf(PR_STDERR, "Failed : NSS_Shutdown()\n");
+ rv = SECFailure;
+ }
+ PR_Cleanup();
+
+ return rv;
+ } \ No newline at end of file
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
diff --git a/security/nss/doc/rst/legacy/nss_sample_code/encrypt_decrypt_mac_using_token/index.rst b/security/nss/doc/rst/legacy/nss_sample_code/encrypt_decrypt_mac_using_token/index.rst
new file mode 100644
index 0000000000..712823698d
--- /dev/null
+++ b/security/nss/doc/rst/legacy/nss_sample_code/encrypt_decrypt_mac_using_token/index.rst
@@ -0,0 +1,1206 @@
+.. _mozilla_projects_nss_nss_sample_code_encrypt_decrypt_mac_using_token:
+
+Encrypt Decrypt_MAC_Using Token
+===============================
+
+.. _nss_sample_code_3_encryptiondecryption_and_mac_using_token_object.:
+
+`NSS Sample Code 3: Encryption/Decryption and MAC Using Token Object. <#nss_sample_code_3_encryptiondecryption_and_mac_using_token_object.>`__
+----------------------------------------------------------------------------------------------------------------------------------------------
+
+.. container::
+
+ Generates encryption/mac keys and uses token for storing.
+
+ .. 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
+ #include
+ #include
+ #include
+ #include
+ #include
+ #include
+
+ /* NSS headers */
+ #include
+ #include
+
+ /* Our samples utilities */
+ #include "util.h"
+
+ #define BUFFERSIZE 80
+ #define DIGESTSIZE 16
+ #define PTEXT_MAC_BUFFER_SIZE 96
+ #define CIPHERSIZE 96
+ #define BLOCKSIZE 32
+
+ #define CIPHER_HEADER "-----BEGIN CIPHER-----"
+ #define CIPHER_TRAILER "-----END CIPHER-----"
+ #define ENCKEY_HEADER "-----BEGIN AESKEY CKAID-----"
+ #define ENCKEY_TRAILER "-----END AESKEY CKAID-----"
+ #define MACKEY_HEADER "-----BEGIN MACKEY CKAID-----"
+ #define MACKEY_TRAILER "-----END MACKEY CKAID-----"
+ #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-----"
+
+ typedef enum {
+ ENCRYPT,
+ DECRYPT,
+ UNKNOWN
+ } CommandType;
+
+ typedef enum {
+ SYMKEY = 0,
+ MACKEY = 1,
+ IV = 2,
+ MAC = 3,
+ PAD = 4
+ } HeaderType;
+
+
+ /*
+ * Print usage message and exit.
+ */
+ static void
+ Usage(const char *progName)
+ {
+ fprintf(stderr, "\nUsage: %s -c -d [-z ] "
+ "[-p | -f ] -i -o \n\n",
+ progName);
+ fprintf(stderr, "%-20s Specify 'a' for encrypt operation\n\n",
+ "-c ");
+ fprintf(stderr, "%-20s Specify 'b' for decrypt operation\n\n",
+ " ");
+ fprintf(stderr, "%-20s Specify db directory path\n\n",
+ "-d ");
+ fprintf(stderr, "%-20s Specify db password [optional]\n\n",
+ "-p ");
+ fprintf(stderr, "%-20s Specify db password file [optional]\n\n",
+ "-f ");
+ fprintf(stderr, "%-20s Specify noise file name [optional]\n\n",
+ "-z ");
+ fprintf(stderr, "%-21s Specify an input file name\n\n",
+ "-i ");
+ fprintf(stderr, "%-21s Specify an output file name\n\n",
+ "-o ");
+ fprintf(stderr, "%-7s For encrypt, it takes as an input file and produces\n",
+ "Note :");
+ fprintf(stderr, "%-7s .enc and .header as intermediate output files.\n\n",
+ "");
+ fprintf(stderr, "%-7s For decrypt, it takes .enc and .header\n",
+ "");
+ fprintf(stderr, "%-7s as input files and produces as a final output file.\n\n",
+ "");
+ exit(-1);
+ }
+
+ /*
+ * Gather a CKA_ID.
+ */
+ SECStatus
+ GatherCKA_ID(PK11SymKey* key, SECItem* buf)
+ {
+ SECStatus rv = PK11_ReadRawAttribute(PK11_TypeSymKey, key, CKA_ID, buf);
+ if (rv != SECSuccess) {
+ PR_fprintf(PR_STDERR, "PK11_ReadRawAttribute returned (%d)\n", rv);
+ PR_fprintf(PR_STDERR, "Could not read SymKey CKA_ID attribute\n");
+ return rv;
+ }
+ return rv;
+ }
+
+ /*
+ * Generate a Symmetric Key.
+ */
+ PK11SymKey *
+ GenerateSYMKey(PK11SlotInfo *slot, CK_MECHANISM_TYPE mechanism,
+ int keySize, SECItem *keyID, secuPWData *pwdata)
+ {
+ SECStatus rv;
+ PK11SymKey *key;
+
+ 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));
+ return NULL;
+ }
+ }
+
+ /* Generate the symmetric key. */
+ key = PK11_TokenKeyGen(slot, mechanism,
+ NULL, keySize, keyID, PR_TRUE, pwdata);
+
+ if (!key) {
+ PR_fprintf(PR_STDERR, "Symmetric Key Generation Failed \n");
+ }
+
+ return key;
+ }
+
+ /*
+ * MacInit
+ */
+ SECStatus
+ MacInit(PK11Context *ctx)
+ {
+ SECStatus rv = PK11_DigestBegin(ctx);
+ if (rv != SECSuccess) {
+ PR_fprintf(PR_STDERR, "Compute MAC Failed : PK11_DigestBegin()\n");
+ }
+ return rv;
+ }
+
+ /*
+ * MacUpdate
+ */
+ SECStatus
+ MacUpdate(PK11Context *ctx,
+ unsigned char *msg, unsigned int msgLen)
+ {
+ SECStatus rv = PK11_DigestOp(ctx, msg, msgLen);
+ if (rv != SECSuccess) {
+ PR_fprintf(PR_STDERR, "Compute MAC Failed : DigestOp()\n");
+ }
+ return rv;
+ }
+
+ /*
+ * Finalize MACing.
+ */
+ SECStatus
+ MacFinal(PK11Context *ctx,
+ unsigned char *mac, unsigned int *macLen, unsigned int maxLen)
+ {
+ SECStatus rv = PK11_DigestFinal(ctx, mac, macLen, maxLen);
+ if (rv != SECSuccess) {
+ PR_fprintf(PR_STDERR, "Compute MAC Failed : PK11_DigestFinal()\n");
+ }
+ return SECSuccess;
+ }
+
+ /*
+ * Compute Mac.
+ */
+ SECStatus
+ ComputeMac(PK11Context *ctxmac,
+ unsigned char *ptext, unsigned int ptextLen,
+ unsigned char *mac, unsigned int *macLen,
+ unsigned int maxLen)
+ {
+ SECStatus rv = MacInit(ctxmac);
+ if (rv != SECSuccess) return rv;
+ rv = MacUpdate(ctxmac, ptext, ptextLen);
+ if (rv != SECSuccess) return rv;
+ rv = MacFinal(ctxmac, mac, macLen, maxLen);
+ return rv;
+ }
+
+ /*
+ * WriteToHeaderFile
+ */
+ SECStatus
+ WriteToHeaderFile(const char *buf, unsigned int len, HeaderType type,
+ PRFileDesc *outFile)
+ {
+ SECStatus rv;
+ char header[40];
+ char trailer[40];
+ char *outString = NULL;
+
+ switch (type) {
+ case SYMKEY:
+ strcpy(header, ENCKEY_HEADER);
+ strcpy(trailer, ENCKEY_TRAILER);
+ break;
+ case MACKEY:
+ strcpy(header, MACKEY_HEADER);
+ strcpy(trailer, MACKEY_TRAILER);
+ break;
+ case IV:
+ strcpy(header, IV_HEADER);
+ strcpy(trailer, IV_TRAILER);
+ break;
+ case MAC:
+ strcpy(header, MAC_HEADER);
+ strcpy(trailer, MAC_TRAILER);
+ break;
+ case PAD:
+ strcpy(header, PAD_HEADER);
+ strcpy(trailer, PAD_TRAILER);
+ break;
+ }
+
+ PR_fprintf(outFile, "%s\n", header);
+ PrintAsHex(outFile, buf, len);
+ PR_fprintf(outFile, "%s\n\n", trailer);
+ return SECSuccess;
+ }
+
+ /*
+ * Initialize for encryption or decryption - common code.
+ */
+ PK11Context *
+ CryptInit(PK11SymKey *key,
+ unsigned char *iv, unsigned int ivLen,
+ CK_MECHANISM_TYPE type, CK_ATTRIBUTE_TYPE operation)
+ {
+ SECItem ivItem = { siBuffer, iv, ivLen };
+ PK11Context *ctx = NULL;
+
+ SECItem *secParam = PK11_ParamFromIV(CKM_AES_CBC, &ivItem);
+ if (secParam == NULL) {
+ PR_fprintf(PR_STDERR, "Crypt Failed : secParam NULL\n");
+ return NULL;
+ }
+ ctx = PK11_CreateContextBySymKey(CKM_AES_CBC, operation, key, secParam);
+ if (ctx == NULL) {
+ PR_fprintf(PR_STDERR, "Crypt Failed : can't create a context\n");
+ goto cleanup;
+
+ }
+ cleanup:
+ if (secParam) {
+ SECITEM_FreeItem(secParam, PR_TRUE);
+ }
+ return ctx;
+ }
+
+ /*
+ * Common encryption and decryption code.
+ */
+ SECStatus
+ Crypt(PK11Context *ctx,
+ unsigned char *out, unsigned int *outLen, unsigned int maxOut,
+ unsigned char *in, unsigned int inLen)
+ {
+ SECStatus rv;
+
+ rv = PK11_CipherOp(ctx, out, outLen, maxOut, in, inLen);
+ if (rv != SECSuccess) {
+ PR_fprintf(PR_STDERR, "Crypt Failed : PK11_CipherOp returned %d\n", rv);
+ goto cleanup;
+ }
+
+ cleanup:
+ if (rv != SECSuccess) {
+ return rv;
+ }
+ return SECSuccess;
+ }
+
+ /*
+ * Decrypt
+ */
+ SECStatus
+ Decrypt(PK11Context *ctx,
+ unsigned char *out, unsigned int *outLen, unsigned int maxout,
+ unsigned char *in, unsigned int inLen)
+ {
+ return Crypt(ctx, out, outLen, maxout, in, inLen);
+ }
+
+ /*
+ * Encrypt
+ */
+ SECStatus
+ Encrypt(PK11Context* ctx,
+ unsigned char *out, unsigned int *outLen, unsigned int maxout,
+ unsigned char *in, unsigned int inLen)
+ {
+ return Crypt(ctx, out, outLen, maxout, in, inLen);
+ }
+
+ /*
+ * EncryptInit
+ */
+ PK11Context *
+ EncryptInit(PK11SymKey *ek, unsigned char *iv, unsigned int ivLen,
+ CK_MECHANISM_TYPE type)
+ {
+ return CryptInit(ek, iv, ivLen, type, CKA_ENCRYPT);
+ }
+
+ /*
+ * DecryptInit
+ */
+ PK11Context *
+ DecryptInit(PK11SymKey *dk, unsigned char *iv, unsigned int ivLen,
+ CK_MECHANISM_TYPE type)
+ {
+ return CryptInit(dk, iv, ivLen, type, CKA_DECRYPT);
+ }
+
+ /*
+ * Read cryptographic parameters from the header file.
+ */
+ SECStatus
+ ReadFromHeaderFile(const char *fileName, HeaderType type,
+ SECItem *item, PRBool isHexData)
+ {
+ SECStatus rv;
+ PRFileDesc* file;
+ SECItem filedata;
+ SECItem outbuf;
+ unsigned char *nonbody;
+ unsigned char *body;
+ char header[40];
+ char trailer[40];
+
+ outbuf.type = siBuffer;
+ file = PR_Open(fileName, PR_RDONLY, 0);
+ if (!file) {
+ PR_fprintf(PR_STDERR, "Failed to open %s\n", fileName);
+ return SECFailure;
+ }
+ switch (type) {
+ case SYMKEY:
+ strcpy(header, ENCKEY_HEADER);
+ strcpy(trailer, ENCKEY_TRAILER);
+ break;
+ case MACKEY:
+ strcpy(header, MACKEY_HEADER);
+ strcpy(trailer, MACKEY_TRAILER);
+ break;
+ case IV:
+ strcpy(header, IV_HEADER);
+ strcpy(trailer, IV_TRAILER);
+ break;
+ case MAC:
+ strcpy(header, MAC_HEADER);
+ strcpy(trailer, MAC_TRAILER);
+ break;
+ case PAD:
+ strcpy(header, PAD_HEADER);
+ strcpy(trailer, PAD_TRAILER);
+ break;
+ }
+
+ 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);
+ return SECFailure;
+ }
+ } else {
+ body = nonbody;
+ }
+
+ cleanup:
+ PR_Close(file);
+ HexToBuf(body, item, isHexData);
+ return SECSuccess;
+ }
+
+ /*
+ * EncryptAndMac
+ */
+ SECStatus
+ EncryptAndMac(PRFileDesc *inFile,
+ PRFileDesc *headerFile,
+ PRFileDesc *encFile,
+ PK11SymKey *ek,
+ PK11SymKey *mk,
+ unsigned char *iv, unsigned int ivLen,
+ PRBool ascii)
+ {
+ SECStatus rv;
+ unsigned char ptext[BLOCKSIZE];
+ unsigned int ptextLen;
+ unsigned char mac[DIGESTSIZE];
+ unsigned int macLen;
+ unsigned int nwritten;
+ unsigned char encbuf[BLOCKSIZE];
+ unsigned int encbufLen;
+ SECItem noParams = { siBuffer, NULL, 0 };
+ PK11Context *ctxmac = NULL;
+ PK11Context *ctxenc = NULL;
+ unsigned int pad[1];
+ SECItem padItem;
+ unsigned int paddingLength;
+
+ static unsigned int firstTime = 1;
+ int j;
+
+ ctxmac = PK11_CreateContextBySymKey(CKM_MD5_HMAC, CKA_SIGN, mk, &noParams);
+ if (ctxmac == NULL) {
+ PR_fprintf(PR_STDERR, "Can't create MAC context\n");
+ rv = SECFailure;
+ goto cleanup;
+ }
+ rv = MacInit(ctxmac);
+ if (rv != SECSuccess) {
+ goto cleanup;
+ }
+
+ ctxenc = EncryptInit(ek, iv, ivLen, CKM_AES_CBC);
+
+ /* Read a buffer of plaintext from input file. */
+ while ((ptextLen = PR_Read(inFile, ptext, sizeof(ptext))) > 0) {
+
+ /* Encrypt using it using CBC, using previously created IV. */
+ if (ptextLen != BLOCKSIZE) {
+ paddingLength = BLOCKSIZE - ptextLen;
+ for ( j=0; j < paddingLength; j++) {
+ ptext[ptextLen+j] = (unsigned char)paddingLength;
+ }
+ ptextLen = BLOCKSIZE;
+ }
+ rv = Encrypt(ctxenc,
+ encbuf, &encbufLen, sizeof(encbuf),
+ ptext, ptextLen);
+ if (rv != SECSuccess) {
+ PR_fprintf(PR_STDERR, "Encrypt Failure\n");
+ goto cleanup;
+ }
+
+ /* Save the last block of ciphertext as the next IV. */
+ iv = encbuf;
+ ivLen = encbufLen;
+
+ /* Write the cipher text to intermediate file. */
+ nwritten = PR_Write(encFile, encbuf, encbufLen);
+ /* PR_Assert(nwritten == encbufLen); */
+
+ rv = MacUpdate(ctxmac, ptext, ptextLen);
+ }
+
+ rv = MacFinal(ctxmac, mac, &macLen, DIGESTSIZE);
+ if (rv != SECSuccess) {
+ PR_fprintf(PR_STDERR, "MacFinal Failure\n");
+ goto cleanup;
+ }
+ if (macLen == 0) {
+ PR_fprintf(PR_STDERR, "Bad MAC length\n");
+ rv = SECFailure;
+ goto cleanup;
+ }
+ WriteToHeaderFile(mac, macLen, MAC, headerFile);
+ if (rv != SECSuccess) {
+ PR_fprintf(PR_STDERR, "Write MAC Failure\n");
+ goto cleanup;
+ }
+
+ pad[0] = paddingLength;
+ padItem.type = siBuffer;
+ padItem.data = (unsigned char *)pad;
+ padItem.len = sizeof(pad[0]);
+
+ WriteToHeaderFile(padItem.data, padItem.len, PAD, headerFile);
+ if (rv != SECSuccess) {
+ PR_fprintf(PR_STDERR, "Write PAD Failure\n");
+ goto cleanup;
+ }
+
+ rv = SECSuccess;
+
+ cleanup:
+ if (ctxmac != NULL) {
+ PK11_DestroyContext(ctxmac, PR_TRUE);
+ }
+ if (ctxenc != NULL) {
+ PK11_DestroyContext(ctxenc, PR_TRUE);
+ }
+
+ return rv;
+ }
+
+ /*
+ * Find the Key for the given mechanism.
+ */
+ PK11SymKey*
+ FindKey(PK11SlotInfo *slot,
+ CK_MECHANISM_TYPE mechanism,
+ SECItem *keyBuf, secuPWData *pwdata)
+ {
+ SECStatus rv;
+ PK11SymKey *key;
+
+ 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));
+ if (slot) {
+ PK11_FreeSlot(slot);
+ }
+ return NULL;
+ }
+ }
+
+ key = PK11_FindFixedKey(slot, mechanism, keyBuf, 0);
+ if (!key) {
+ PR_fprintf(PR_STDERR,
+ "PK11_FindFixedKey failed (err %d)\n",
+ PR_GetError());
+ PK11_FreeSlot(slot);
+ return NULL;
+ }
+ return key;
+ }
+
+ /*
+ * Decrypt and Verify MAC.
+ */
+ SECStatus
+ DecryptAndVerifyMac(const char* outFileName,
+ char *encryptedFileName,
+ SECItem *cItem, SECItem *macItem,
+ PK11SymKey* ek, PK11SymKey* mk, SECItem *ivItem, SECItem *padItem)
+ {
+ SECStatus rv;
+ PRFileDesc* inFile;
+ PRFileDesc* outFile;
+
+ unsigned char decbuf[64];
+ unsigned int decbufLen;
+
+ unsigned char ptext[BLOCKSIZE];
+ unsigned int ptextLen = 0;
+ unsigned char ctext[64];
+ unsigned int ctextLen;
+ unsigned char newmac[DIGESTSIZE];
+ unsigned int newmacLen = 0;
+ unsigned int newptextLen = 0;
+ unsigned int count = 0;
+ unsigned int temp = 0;
+ unsigned int blockNumber = 0;
+ SECItem noParams = { siBuffer, NULL, 0 };
+ PK11Context *ctxmac = NULL;
+ PK11Context *ctxenc = NULL;
+
+ unsigned char iv[BLOCKSIZE];
+ unsigned int ivLen = ivItem->len;
+ unsigned int fileLength;
+ unsigned int paddingLength;
+ int j;
+
+ memcpy(iv, ivItem->data, ivItem->len);
+ paddingLength = (unsigned int)padItem->data[0];
+
+ ctxmac = PK11_CreateContextBySymKey(CKM_MD5_HMAC, CKA_SIGN, mk, &noParams);
+ if (ctxmac == NULL) {
+ PR_fprintf(PR_STDERR, "Can't create MAC context\n");
+ rv = SECFailure;
+ goto cleanup;
+ }
+
+ /* Open the input file. */
+ inFile = PR_Open(encryptedFileName, PR_RDONLY , 0);
+ if (!inFile) {
+ PR_fprintf(PR_STDERR,
+ "Unable to open \"%s\" for writing.\n",
+ encryptedFileName);
+ return SECFailure;
+ }
+ /* Open the output file. */
+ 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);
+ return SECFailure;
+ }
+
+ rv = MacInit(ctxmac);
+ if (rv != SECSuccess) goto cleanup;
+
+ ctxenc = DecryptInit(ek, iv, ivLen, CKM_AES_CBC);
+ fileLength = FileSize(encryptedFileName);
+
+ while ((ctextLen = PR_Read(inFile, ctext, sizeof(ctext))) > 0) {
+
+ count += ctextLen;
+
+ /* Decrypt cipher text buffer using CBC and IV. */
+
+ rv = Decrypt(ctxenc, decbuf, &decbufLen, sizeof(decbuf),
+ ctext, ctextLen);
+
+ if (rv != SECSuccess) {
+ PR_fprintf(PR_STDERR, "Decrypt Failure\n");
+ goto cleanup;
+ }
+
+ if (decbufLen == 0) break;
+
+ rv = MacUpdate(ctxmac, decbuf, decbufLen);
+ if (rv != SECSuccess) { goto cleanup; }
+ if (count == fileLength) {
+ 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;
+ }
+
+ /* Save last block of ciphertext. */
+ memcpy(iv, decbuf, decbufLen);
+ ivLen = decbufLen;
+ blockNumber++;
+ }
+
+ if (rv != SECSuccess) { goto cleanup; }
+
+ rv = MacFinal(ctxmac, newmac, &newmacLen, sizeof(newmac));
+ if (rv != SECSuccess) { goto cleanup; }
+
+ if (PORT_Memcmp(macItem->data, newmac, newmacLen) == 0) {
+ rv = SECSuccess;
+ } else {
+ PR_fprintf(PR_STDERR, "Check MAC : Failure\n");
+ PR_fprintf(PR_STDERR, "Extracted : ");
+ PrintAsHex(PR_STDERR, macItem->data, macItem->len);
+ PR_fprintf(PR_STDERR, "Computed : ");
+ PrintAsHex(PR_STDERR, newmac, newmacLen);
+ rv = SECFailure;
+ }
+ cleanup:
+ if (ctxmac) {
+ PK11_DestroyContext(ctxmac, PR_TRUE);
+ }
+ if (ctxenc) {
+ PK11_DestroyContext(ctxenc, PR_TRUE);
+ }
+ if (outFile) {
+ PR_Close(outFile);
+ }
+
+ return rv;
+ }
+
+ /*
+ * Gets IV and CKAIDS from Header File.
+ */
+ SECStatus
+ GetIVandCKAIDSFromHeader(const char *cipherFileName,
+ SECItem *ivItem, SECItem *encKeyItem, SECItem *macKeyItem)
+ {
+ SECStatus rv;
+
+ /* Open intermediate file, read in header, get IV and CKA_IDs of two keys
+ * from it.
+ */
+ rv = ReadFromHeaderFile(cipherFileName, IV, ivItem, PR_TRUE);
+ if (rv != SECSuccess) {
+ PR_fprintf(PR_STDERR, "Could not retrieve IV from cipher file\n");
+ goto cleanup;
+ }
+
+ rv = ReadFromHeaderFile(cipherFileName, SYMKEY, encKeyItem, PR_TRUE);
+ if (rv != SECSuccess) {
+ PR_fprintf(PR_STDERR,
+ "Could not retrieve AES CKA_ID from cipher file\n");
+ goto cleanup;
+ }
+ rv = ReadFromHeaderFile(cipherFileName, MACKEY, macKeyItem, PR_TRUE);
+ if (rv != SECSuccess) {
+ PR_fprintf(PR_STDERR,
+ "Could not retrieve MAC CKA_ID from cipher file\n");
+ goto cleanup;
+ }
+ cleanup:
+ return rv;
+ }
+
+ /*
+ * DecryptFile
+ */
+ SECStatus
+ DecryptFile(PK11SlotInfo *slot,
+ const char *dbdir,
+ const char *outFileName,
+ const char *headerFileName,
+ char *encryptedFileName,
+ secuPWData *pwdata,
+ PRBool ascii)
+ {
+ /*
+ * The DB is open read only and we have authenticated to it:
+ * Open input file, read in header, get IV and CKA_IDs of two keys from it.
+ * Find those keys in the DB token.
+ * Open output file.
+ * Loop until EOF(input):
+ * Read a buffer of ciphertext from input file.
+ * Save last block of ciphertext.
+ * Decrypt ciphertext buffer using CBC and IV.
+ * Compute and check MAC, then remove MAC from plaintext.
+ * Replace IV with saved last block of ciphertext.
+ * Write the plain text to output file.
+ * Close files.
+ * Report success.
+ */
+
+ SECStatus rv;
+ SECItem ivItem;
+ SECItem encKeyItem;
+ SECItem macKeyItem;
+ SECItem cipherItem;
+ SECItem macItem;
+ SECItem padItem;
+ PK11SymKey *encKey = NULL;
+ PK11SymKey *macKey = NULL;
+
+
+ /* Open intermediate file, read in header, get IV and CKA_IDs of two keys
+ * from it.
+ */
+ rv = GetIVandCKAIDSFromHeader(headerFileName,
+ &ivItem, &encKeyItem, &macKeyItem);
+ if (rv != SECSuccess) {
+ goto cleanup;
+ }
+
+ /* Find those keys in the DB token. */
+ encKey = FindKey(slot, CKM_AES_CBC, &encKeyItem, pwdata);
+ if (encKey == NULL) {
+ PR_fprintf(PR_STDERR, "Can't find the encryption key\n");
+ rv = SECFailure;
+ goto cleanup;
+ }
+ /* CKM_MD5_HMAC or CKM_EXTRACT_KEY_FROM_KEY */
+ macKey = FindKey(slot, CKM_MD5_HMAC, &macKeyItem, pwdata);
+ if (macKey == NULL) {
+ rv = SECFailure;
+ goto cleanup;
+ }
+
+ /* Read in the Mac into item from the intermediate file. */
+ rv = ReadFromHeaderFile(headerFileName, MAC, &macItem, PR_TRUE);
+ if (rv != SECSuccess) {
+ PR_fprintf(PR_STDERR,
+ "Could not retrieve MAC from cipher file\n");
+ goto cleanup;
+ }
+ if (macItem.data == NULL) {
+ PR_fprintf(PR_STDERR, "MAC has NULL data\n");
+ rv = SECFailure;
+ goto cleanup;
+ }
+ if (macItem.len == 0) {
+ PR_fprintf(PR_STDERR, "MAC has data has 0 length\n");
+ /*rv = SECFailure;
+ goto cleanup;*/
+ }
+
+ 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;
+ }
+
+ if (rv == SECSuccess) {
+ /* Decrypt and Remove Mac */
+ rv = DecryptAndVerifyMac(outFileName, encryptedFileName,
+ &cipherItem, &macItem, encKey, macKey, &ivItem, &padItem);
+ if (rv != SECSuccess) {
+ PR_fprintf(PR_STDERR, "Failed while decrypting and removing MAC\n");
+ }
+ }
+
+ cleanup:
+ if (slot) {
+ PK11_FreeSlot(slot);
+ }
+ if (encKey) {
+ PK11_FreeSymKey(encKey);
+ }
+ if (macKey) {
+ PK11_FreeSymKey(macKey);
+ }
+
+ return rv;
+ }
+
+ /*
+ * EncryptFile
+ */
+ SECStatus
+ EncryptFile(PK11SlotInfo *slot,
+ const char *dbdir,
+ const char *inFileName,
+ const char *headerFileName,
+ const char *encryptedFileName,
+ const char *noiseFileName,
+ secuPWData *pwdata,
+ PRBool ascii)
+ {
+ /*
+ * The DB is open for read/write and we have authenticated to it.
+ * generate a symmetric AES key as a token object.
+ * generate a second key to use for MACing, also a token object.
+ * get their CKA_IDs
+ * generate a random value to use as IV for AES CBC
+ * open an input file and an output file,
+ * write a header to the output that identifies the two keys by
+ * their CKA_IDs, May include original file name and length.
+ * loop until EOF(input)
+ * read a buffer of plaintext from input file,
+ * MAC it, append the MAC to the plaintext
+ * encrypt it using CBC, using previously created IV,
+ * store the last block of ciphertext as the new IV,
+ * write the cipher text to intermediate file
+ * close files
+ * report success
+ */
+ SECStatus rv;
+ PRFileDesc *inFile;
+ PRFileDesc *headerFile;
+ PRFileDesc *encFile;
+
+ unsigned char *encKeyId = (unsigned char *) "Encrypt Key";
+ unsigned char *macKeyId = (unsigned char *) "MAC Key";
+ SECItem encKeyID = { siAsciiString, encKeyId, PL_strlen(encKeyId) };
+ SECItem macKeyID = { siAsciiString, macKeyId, PL_strlen(macKeyId) };
+
+ SECItem encCKAID;
+ SECItem macCKAID;
+ unsigned char iv[BLOCKSIZE];
+ SECItem ivItem;
+ PK11SymKey *encKey = NULL;
+ PK11SymKey *macKey = NULL;
+ SECItem temp;
+ unsigned char c;
+
+ /* Generate a symmetric AES key as a token object. */
+ encKey = GenerateSYMKey(slot, CKM_AES_KEY_GEN, 128/8, &encKeyID, pwdata);
+ if (encKey == NULL) {
+ PR_fprintf(PR_STDERR, "GenerateSYMKey for AES returned NULL.\n");
+ rv = SECFailure;
+ goto cleanup;
+ }
+
+ /* Generate a second key to use for MACing, also a token object. */
+ macKey = GenerateSYMKey(slot, CKM_GENERIC_SECRET_KEY_GEN, 160/8,
+ &macKeyID, pwdata);
+ if (macKey == NULL) {
+ PR_fprintf(PR_STDERR, "GenerateSYMKey for MACing returned NULL.\n");
+ rv = SECFailure;
+ goto cleanup;
+ }
+
+ /* Get the encrypt key CKA_ID */
+ rv = GatherCKA_ID(encKey, &encCKAID);
+ if (rv != SECSuccess) {
+ PR_fprintf(PR_STDERR, "Error while wrapping encrypt key\n");
+ goto cleanup;
+ }
+
+ /* Get the MAC key CKA_ID */
+ rv = GatherCKA_ID(macKey, &macCKAID);
+ if (rv != SECSuccess) {
+ PR_fprintf(PR_STDERR, "Can't get the MAC key CKA_ID.\n");
+ goto cleanup;
+ }
+
+ if (noiseFileName) {
+ rv = SeedFromNoiseFile(noiseFileName);
+ if (rv != SECSuccess) {
+ PORT_SetError(PR_END_OF_FILE_ERROR);
+ return SECFailure;
+ }
+ rv = PK11_GenerateRandom(iv, BLOCKSIZE);
+ if (rv != SECSuccess) {
+ goto cleanup;
+ }
+
+ } else {
+ /* Generate a random value to use as IV for AES CBC. */
+ GenerateRandom(iv, BLOCKSIZE);
+ }
+
+ headerFile = PR_Open(headerFileName,
+ PR_CREATE_FILE | PR_TRUNCATE | PR_RDWR, 00660);
+ if (!headerFile) {
+ PR_fprintf(PR_STDERR,
+ "Unable to open \"%s\" for writing.\n",
+ headerFileName);
+ return SECFailure;
+ }
+ 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);
+ return SECFailure;
+ }
+ /* Write to a header file the IV and the CKA_IDs
+ * identifying the two keys.
+ */
+ ivItem.type = siBuffer;
+ ivItem.data = iv;
+ ivItem.len = BLOCKSIZE;
+
+ rv = WriteToHeaderFile(iv, BLOCKSIZE, IV, headerFile);
+ if (rv != SECSuccess) {
+ PR_fprintf(PR_STDERR, "Error writing IV to cipher file - %s\n",
+ headerFileName);
+ goto cleanup;
+ }
+
+ rv = WriteToHeaderFile(encCKAID.data, encCKAID.len, SYMKEY, headerFile);
+ if (rv != SECSuccess) {
+ PR_fprintf(PR_STDERR, "Error writing AES CKA_ID to cipher file - %s\n",
+ encryptedFileName);
+ goto cleanup;
+ }
+ rv = WriteToHeaderFile(macCKAID.data, macCKAID.len, MACKEY, headerFile);
+ if (rv != SECSuccess) {
+ PR_fprintf(PR_STDERR, "Error writing MAC CKA_ID to cipher file - %s\n",
+ headerFileName);
+ goto cleanup;
+ }
+
+ /* 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);
+ return SECFailure;
+ }
+
+ /* Macing and Encryption */
+ if (rv == SECSuccess) {
+ rv = EncryptAndMac(inFile, headerFile, encFile,
+ encKey, macKey, ivItem.data, ivItem.len, ascii);
+ if (rv != SECSuccess) {
+ PR_fprintf(PR_STDERR, "Failed : Macing and Encryption\n");
+ goto cleanup;
+ }
+ }
+
+ cleanup:
+ if (inFile) {
+ PR_Close(inFile);
+ }
+ if (headerFile) {
+ PR_Close(headerFile);
+ }
+ if (encFile) {
+ PR_Close(encFile);
+ }
+ if (slot) {
+ PK11_FreeSlot(slot);
+ }
+ if (encKey) {
+ PK11_FreeSymKey(encKey);
+ }
+ if (macKey) {
+ PK11_FreeSymKey(macKey);
+ }
+
+ return rv;
+ }
+
+ /*
+ * This example illustrates basic encryption/decryption and MACing.
+ * Generates the encryption/mac keys and uses token for storing.
+ * Encrypts the input file and appends MAC before storing in intermediate
+ * header file.
+ * Writes the CKA_IDs of the encryption keys into intermediate header file.
+ * Reads the intermediate headerfile for CKA_IDs and encrypted
+ * contents and decrypts into output file.
+ */
+ int
+ main(int argc, char **argv)
+ {
+ SECStatus rv;
+ SECStatus rvShutdown;
+ PK11SlotInfo *slot = NULL;
+ PLOptState *optstate;
+ PLOptStatus status;
+ char headerFileName[50];
+ char encryptedFileName[50];
+ PRFileDesc *inFile;
+ PRFileDesc *outFile;
+ PRBool ascii = PR_FALSE;
+ CommandType cmd = UNKNOWN;
+ const char *command = NULL;
+ const char *dbdir = NULL;
+ const char *inFileName = NULL;
+ const char *outFileName = NULL;
+ const char *noiseFileName = NULL;
+ secuPWData pwdata = { PW_NONE, 0 };
+
+ char * progName = strrchr(argv[0], '/');
+ progName = progName ? progName + 1 : argv[0];
+
+ /* Parse command line arguments */
+ optstate = PL_CreateOptState(argc, argv, "c:d:i:o:f:p:z:a");
+ while ((status = PL_GetNextOpt(optstate)) == PL_OPT_OK) {
+ switch (optstate->option) {
+ case 'a':
+ ascii = PR_TRUE;
+ break;
+ case 'c':
+ command = strdup(optstate->value);
+ 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 'o':
+ outFileName = strdup(optstate->value);
+ break;
+ case 'z':
+ noiseFileName = strdup(optstate->value);
+ break;
+ default:
+ Usage(progName);
+ break;
+ }
+ }
+ PL_DestroyOptState(optstate);
+
+ if (!command || !dbdir || !inFileName || !outFileName)
+ Usage(progName);
+ if (PL_strlen(command)==0)
+ Usage(progName);
+
+ cmd = command[0] == 'a' ? ENCRYPT : command[0] == 'b' ? DECRYPT : UNKNOWN;
+
+ /* 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);
+ return SECFailure;
+ }
+ PR_Close(inFile);
+
+ /* For intermediate header file, choose filename as inputfile name
+ with extension ".header" */
+ strcpy(headerFileName, inFileName);
+ strcat(headerFileName, ".header");
+
+ /* For intermediate encrypted file, choose filename as inputfile name
+ with extension ".enc" */
+ strcpy(encryptedFileName, inFileName);
+ strcat(encryptedFileName, ".enc");
+
+ PR_Init(PR_USER_THREAD, PR_PRIORITY_NORMAL, 0);
+
+ switch (cmd) {
+ case ENCRYPT:
+ /* If the intermediate header file already exists, delete it. */
+ if (PR_Access(headerFileName, PR_ACCESS_EXISTS) == PR_SUCCESS) {
+ PR_Delete(headerFileName);
+ }
+ /* If the intermediate encrypted already exists, delete it. */
+ if (PR_Access(encryptedFileName, PR_ACCESS_EXISTS) == PR_SUCCESS) {
+ PR_Delete(encryptedFileName);
+ }
+
+ /* Open DB for read/write and authenticate to it. */
+ 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;
+ }
+ }
+ rv = EncryptFile(slot, dbdir,
+ inFileName, headerFileName, encryptedFileName,
+ noiseFileName, &pwdata, ascii);
+ if (rv != SECSuccess) {
+ PR_fprintf(PR_STDERR, "EncryptFile : Failed\n");
+ return SECFailure;
+ }
+ break;
+ case DECRYPT:
+ /* Open DB read only, authenticate to it. */
+ PK11_SetPasswordFunc(GetModulePassword);
+
+ rv = NSS_Init(dbdir);
+ if (rv != SECSuccess) {
+ PR_fprintf(PR_STDERR, "NSS_Init Failed\n");
+ return SECFailure;
+ }
+
+ 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;
+ }
+ }
+
+ rv = DecryptFile(slot, dbdir,
+ outFileName, headerFileName,
+ encryptedFileName, &pwdata, ascii);
+ if (rv != SECSuccess) {
+ PR_fprintf(PR_STDERR, "DecryptFile : Failed\n");
+ return SECFailure;
+ }
+ break;
+ }
+
+ cleanup:
+ rvShutdown = NSS_Shutdown();
+ if (rvShutdown != SECSuccess) {
+ PR_fprintf(PR_STDERR, "Failed : NSS_Shutdown()\n");
+ rv = SECFailure;
+ }
+
+ PR_Cleanup();
+
+ return rv;
+ } \ No newline at end of file
diff --git a/security/nss/doc/rst/legacy/nss_sample_code/index.rst b/security/nss/doc/rst/legacy/nss_sample_code/index.rst
new file mode 100644
index 0000000000..88f1e7bdab
--- /dev/null
+++ b/security/nss/doc/rst/legacy/nss_sample_code/index.rst
@@ -0,0 +1,31 @@
+.. _mozilla_projects_nss_nss_sample_code:
+
+NSS Sample Code
+===============
+
+.. container::
+
+ The collection of sample code here demonstrates how NSS can be used for cryptographic operations,
+ certificate handling, SSL, etc. It also demonstrates some best practices in the application of
+ cryptography.
+
+ Old samples in the process of being replaced.
+
+ #. :ref:`mozilla_projects_nss_sample_code_sample1`
+ #. :ref:`mozilla_projects_nss_sample_code_sample2`
+ #. :ref:`mozilla_projects_nss_sample_code_sample3`
+ #. :ref:`mozilla_projects_nss_sample_code_sample4`
+ #. :ref:`mozilla_projects_nss_sample_code_sample5`
+ #. :ref:`mozilla_projects_nss_sample_code_sample6`
+
+ |
+ | These are very old examples in need of replacement. See
+ https://bugzilla.mozilla.org/show_bug.cgi?id=490238
+
+ You are welcome to download the new samples via:
+
+ .. code:: sh
+
+ hg clone https://hg.mozilla.org/projects/nss; cd nss; hg update SAMPLES_BRANCH
+
+ The new samples: :ref:`mozilla_projects_nss_new_nss_samples` \ No newline at end of file
diff --git a/security/nss/doc/rst/legacy/nss_sample_code/nss_sample_code_sample1/index.rst b/security/nss/doc/rst/legacy/nss_sample_code/nss_sample_code_sample1/index.rst
new file mode 100644
index 0000000000..10926903af
--- /dev/null
+++ b/security/nss/doc/rst/legacy/nss_sample_code/nss_sample_code_sample1/index.rst
@@ -0,0 +1,713 @@
+.. _mozilla_projects_nss_nss_sample_code_nss_sample_code_sample1:
+
+NSS Sample Code Sample1
+=======================
+
+.. _nss_sample_code_1_key_generation_and_transport_between_servers.:
+
+`NSS Sample Code 1: Key Generation and Transport Between Servers. <#nss_sample_code_1_key_generation_and_transport_between_servers.>`__
+---------------------------------------------------------------------------------------------------------------------------------------
+
+.. container::
+
+ This is an example program that demonstrates how to do key generation and transport between
+ cooperating servers. This program shows the following:
+
+ - RSA key pair generation
+ - Naming RSA key pairs
+ - Looking up a previously generated key pair by name
+ - Creating AES and MAC keys (or encryption and MAC keys in general)
+ - Wrapping symmetric keys using your own RSA key pair so that they can be stored on disk or in a
+ database.
+
+ - As an alternative to TOKEN symmetric keys
+
+ - As a way to store large numbers of symmetric keys
+
+ - Wrapping symmetric keys using an RSA key from another server
+ - Unwrapping keys using your own RSA key pair
+
+ | The main part of the program shows a typical sequence of events for two servers that are trying
+ to extablish a shared key pair.
+ | We will add message protection (encryption and MACing) examples to this program in the future.
+
+.. _sample_code:
+
+`Sample Code <#sample_code>`__
+~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
+
+.. container::
+
+ .. code::
+
+ #include <iostream.h>
+ #include "pk11pub.h"
+ #include "keyhi.h"
+ #include "nss.h"
+
+ // Key management for keys share among multiple hosts
+ //
+ // This example shows how to use NSS functions to create and
+ // distribute keys that need to be shared among multiple servers
+ // or hosts.
+ //
+ // The management scheme assumes that one host is PRIMARY. It
+ // generates the secret keys that will be used by all participating
+ // hosts. The other hosts (SECONDARY) request keys from the
+ // primary host. As an alternative, new keys may be sent to the
+ // current set of SECONDARY hosts when they are generated by the
+ // PRIMARY. In this case, the PRIMARY maintains a list of the
+ // secondary hosts.
+ //
+ // The sequence of events is:
+ // 1. The primary host generates a new symmetric key. This key
+ // may be used for an encryption mechanism (DES or AES) or for
+ // integrity (MD5_HMAC or SHA1_HMAC). This key needs to be
+ // permanent, since it may be used during several runs of the
+ // server. (Currently NSS doesn't store persistant keys. Steps
+ // 1a through 1x show how to do this).
+ // 1a. The primary host generates an RSA keypair that will be used
+ // store keys locally.
+ // 1b. The primary host wraps the newly generated key using the
+ // RSA key and stores the wrapped key data in a local file.
+ // 1c. The primary host unwraps the key using the RSA key each time
+ // access to the key is required, such as at server startup.
+ // 2. The secondary host generates an RSA keypair that will be used
+ // to transport keys between the primary host and itself. This
+ // key needs to exist long enough to be used to process the
+ // response to a key transport request that is made to the primary
+ // server. The example here shows how to create a permanent (token)
+ // RSA key for this purpose. (This key will also be used for
+ // storage of the keys, since NSS does not support permanent symmetric
+ // keys at the current time.)
+ // 3. The secondary host sends its RSA public key to the primary host as
+ // part of a request for a particular key, or to be added to a list
+ // of secondary hosts.
+ // 4. The administrator of the primary host verifies that the RSA key
+ // that was received belongs to a valid secondary host. The adminstrator
+ // may do this by checking that the key was received in a signed email
+ // message, or by checking a digest value with the adminstrator of the
+ // secondary host. [Need support for digest check values]
+ // 5. The primary host exports (wraps) the symmetric key using the
+ // secondary host's RSA key. The wrapped value is sent back to
+ // the secondary host.
+ // 6. The administrator of the secondary host verifies that the wrapped
+ // key data came from the primary host. The same methods outlined
+ // in step 4 may be used here.
+ // 7. The secondary host unwraps the key using its own RSA private key.
+ // NOTE: currently NSS does not support permanent symmetric keys.
+ // The secondary host may store the wrapped value that was received
+ // from the primary in a file, and unwrap it each time the key is required
+ // (such as at server startup).
+
+ // NSS actually has some support for permanent symmetric keys. However this
+ // example will need to be modified somewhat in order to demonstrate it.
+
+ // Utility function to print hex data
+ static void
+ printBuffer(unsigned char *digest, unsigned int len)
+ {
+ int i;
+
+ cout << "length: " << len << endl;
+ for(i = 0;i < len;i++) printf("%02x ", digest[i]);
+ cout << endl;
+ }
+
+ // XXX Data protection
+ // - takes an input buffer, applies the encryption
+ // and MAC, and generates a buffer with the result.
+ // - the application sends or uses the result (possibly
+ // after base64 encoding it.
+
+ //
+ // Server - an instance of a server that is part of a
+ // cluster of servers that are sharing a common set
+ // of encryption and MACing keys.
+ //
+ class Server
+ {
+ public:
+ // Initializes the server instance. In particular, this
+ // creates the key pair that is used for wrapping keys
+ int Init();
+
+ // Generates keys for encryption (AES) and MACing. The
+ // wrapped keys are stored in data files.
+ int GenerateKeys();
+
+ // Gets the server's public key (wrapping key) to
+ // send to another server. This becomes the input to
+ // the ExportKeys method on the remote server.
+ int ExportPublicKey(SECItem **pubKeyData);
+
+ // Export the encryption and key using the key
+ // provided. The key should come from another server
+ // in the cluster. (The admin should verify this.)
+ //
+ // In this example, the server must be started to perform
+ // this function (see Start())
+ int ExportKeys(SECItem *pubKey, SECItem **wrappedEncKey,
+ SECItem **wrappedMacKey);
+
+ // Import the keys received from another server in the
+ // cluster. The admin should make sure the keys actually
+ // came from the correct source.
+ int ImportKeys(SECItem *wrappedEncKey, SECItem *wrappedMacKey);
+
+ // Start the server, loading the encryption and MACing keys
+ // from files
+ int Start();
+
+ // Shut down the server. (For completeness)
+ int Shutdown();
+
+ // Compare keys in two server instances. Use this in the
+ // example to make sure the keys are transferred correctly.
+ // This will not work in real life!
+ //
+ // The servers must be started
+ int CompareKeys(Server *peer);
+
+ // Create a server - the name distiguish the keys in the
+ // shared database in this example
+ Server(const char *serverName);
+ ~Server();
+
+ private:
+ int getPrivateKey(SECKEYPrivateKey **prvKey);
+ int getPublicKey(SECKEYPublicKey **pubKey);
+ int wrapKey(PK11SymKey *key, SECKEYPublicKey *pubKey, SECItem **data);
+
+ // export raw key (unwrapped) DO NOT USE
+ int rawExportKey(PK11SymKey *key, SECItem **data);
+
+ char *mServerName;
+
+ // These items represent data that might be stored
+ // in files or in a configuration file
+ SECItem *mWrappedEncKey;
+ SECItem *mWrappedMacKey;
+
+ // These are the runtime keys as loaded from the files
+ PK11SymKey *mEncKey;
+ PK11SymKey *mMacKey;
+ };
+
+ Server::Server(const char *serverName)
+ : mServerName(0), mWrappedEncKey(0), mWrappedMacKey(0),
+ mEncKey(0), mMacKey(0)
+ {
+ // Copy the server name
+ mServerName = PL_strdup(serverName);
+ }
+
+ Server::~Server()
+ {
+ if (mServerName) PL_strfree(mServerName);
+ if (mWrappedEncKey) SECITEM_FreeItem(mWrappedEncKey, PR_TRUE);
+ if (mWrappedMacKey) SECITEM_FreeItem(mWrappedMacKey, PR_TRUE);
+ if (mEncKey) PK11_FreeSymKey(mEncKey);
+ if (mMacKey) PK11_FreeSymKey(mMacKey);
+ }
+
+ int
+ Server::Init()
+ {
+ int rv = 0;
+ SECKEYPrivateKey *prvKey = 0;
+ SECKEYPublicKey *pubKey = 0;
+ PK11SlotInfo *slot = 0;
+ PK11RSAGenParams rsaParams;
+ SECStatus s;
+
+ // See if there is already a private key with this name.
+ // If there is one, no further action is required.
+ rv = getPrivateKey(&prvKey);
+ if (rv == 0 && prvKey) goto done;
+
+ rv = 0;
+
+ // These could be parameters to the Init function
+ rsaParams.keySizeInBits = 1024;
+ rsaParams.pe = 65537;
+
+ slot = PK11_GetInternalKeySlot();
+ if (!slot) { rv = 1; goto done; }
+
+ prvKey = PK11_GenerateKeyPair(slot, CKM_RSA_PKCS_KEY_PAIR_GEN, &rsaParams,
+ &pubKey, PR_TRUE, PR_TRUE, 0);
+ if (!prvKey) { rv = 1; goto done; }
+
+ // Set the nickname on the private key so that it
+ // can be found later.
+ s = PK11_SetPrivateKeyNickname(prvKey, mServerName);
+ if (s != SECSuccess) { rv = 1; goto done; }
+
+ done:
+ if (slot) PK11_FreeSlot(slot);
+ if (pubKey) SECKEY_DestroyPublicKey(pubKey);
+ if (prvKey) SECKEY_DestroyPrivateKey(prvKey);
+
+ return rv;
+ }
+
+ int
+ Server::GenerateKeys()
+ {
+ int rv = 0;
+ SECKEYPublicKey *pubKey = 0;
+ PK11SlotInfo *slot = 0;
+
+ // Choose a slot to use
+ slot = PK11_GetInternalKeySlot();
+ if (!slot) { rv = 1; goto done; }
+
+ // Get our own public key to use for wrapping
+ rv = getPublicKey(&pubKey);
+ if (rv) goto done;
+
+ // Do the Encryption (AES) key
+ if (!mWrappedEncKey)
+ {
+ PK11SymKey *key = 0;
+
+ // The key size is 128 bits (16 bytes)
+ key = PK11_KeyGen(slot, CKM_AES_KEY_GEN, 0, 128/8, 0);
+ if (!key) { rv = 1; goto aes_done; }
+
+ rv = wrapKey(key, pubKey, &mWrappedEncKey);
+
+ aes_done:
+ if (key) PK11_FreeSymKey(key);
+
+ if (rv) goto done;
+ }
+
+ // Do the Mac key
+ if (!mWrappedMacKey)
+ {
+ PK11SymKey *key = 0;
+
+ // The key size is 160 bits (20 bytes)
+ key = PK11_KeyGen(slot, CKM_GENERIC_SECRET_KEY_GEN, 0, 160/8, 0);
+ if (!key) { rv = 1; goto mac_done; }
+
+ rv = wrapKey(key, pubKey, &mWrappedMacKey);
+
+ mac_done:
+ if (key) PK11_FreeSymKey(key);
+ }
+
+ done:
+ if (slot) PK11_FreeSlot(slot);
+
+ return rv;
+ }
+
+ int
+ Server::ExportPublicKey(SECItem **pubKeyData)
+ {
+ int rv = 0;
+ SECKEYPublicKey *pubKey = 0;
+
+ rv = getPublicKey(&pubKey);
+ if (rv) goto done;
+
+ *pubKeyData = SECKEY_EncodeDERSubjectPublicKeyInfo(pubKey);
+ if (!*pubKeyData) { rv = 1; goto done; }
+
+ done:
+ if (pubKey) SECKEY_DestroyPublicKey(pubKey);
+
+ return rv;
+ }
+
+ int
+ Server::ExportKeys(SECItem *pubKeyData, SECItem **wrappedEncKey,
+ SECItem **wrappedMacKey)
+ {
+ int rv;
+ CERTSubjectPublicKeyInfo *keyInfo = 0;
+ SECKEYPublicKey *pubKey = 0;
+ SECItem *data = 0;
+
+ // Make sure the keys are available (server running)
+ if (!mEncKey || !mMacKey) { rv = 1; goto done; }
+
+ // Import the public key of the other server
+ keyInfo = SECKEY_DecodeDERSubjectPublicKeyInfo(pubKeyData);
+ if (!keyInfo) { rv = 1; goto done; }
+
+ pubKey = SECKEY_ExtractPublicKey(keyInfo);
+ if (!pubKey) { rv = 1; goto done; }
+
+ // Export the encryption key
+ rv = wrapKey(mEncKey, pubKey, &data);
+ if (rv) goto done;
+
+ // Export the MAC key
+ rv = wrapKey(mMacKey, pubKey, wrappedMacKey);
+ if (rv) goto done;
+
+ // Commit the rest of the operation
+ *wrappedEncKey = data;
+ data = 0;
+
+ done:
+ if (data) SECITEM_FreeItem(data, PR_TRUE);
+ if (pubKey) SECKEY_DestroyPublicKey(pubKey);
+ if (keyInfo) SECKEY_DestroySubjectPublicKeyInfo(keyInfo);
+
+ return rv;
+ }
+
+ int
+ Server::ImportKeys(SECItem *wrappedEncKey, SECItem *wrappedMacKey)
+ {
+ int rv = 0;
+
+ if (mWrappedEncKey || mWrappedMacKey) { rv = 1; goto done; }
+
+ mWrappedEncKey = SECITEM_DupItem(wrappedEncKey);
+ if (!mWrappedEncKey) { rv = 1; goto done; }
+
+ mWrappedMacKey = SECITEM_DupItem(wrappedMacKey);
+ if (!mWrappedMacKey) { rv = 1; goto done; }
+
+ done:
+ return rv;
+ }
+
+ int
+ Server::Start()
+ {
+ int rv;
+ SECKEYPrivateKey *prvKey = 0;
+
+ rv = getPrivateKey(&prvKey);
+ if (rv) goto done;
+
+ if (!mEncKey)
+ {
+ // Unwrap the encryption key from the "file"
+ // This function uses a mechanism rather than a key type
+ // Does this need to be "WithFlags"??
+ mEncKey = PK11_PubUnwrapSymKey(prvKey, mWrappedEncKey,
+ CKM_AES_CBC_PAD, CKA_ENCRYPT, 0);
+ if (!mEncKey) { rv = 1; goto done; }
+ }
+
+ if (!mMacKey)
+ {
+ // Unwrap the MAC key from the "file"
+ // This function uses a mechanism rather than a key type
+ // Does this need to be "WithFlags"??
+ mMacKey = PK11_PubUnwrapSymKey(prvKey, mWrappedMacKey,
+ CKM_MD5_HMAC, CKA_SIGN, 0);
+ if (!mMacKey) { rv = 1; goto done; }
+ }
+
+ done:
+ if (prvKey) SECKEY_DestroyPrivateKey(prvKey);
+
+ return rv;
+ }
+
+ int
+ Server::Shutdown()
+ {
+ if (mEncKey) PK11_FreeSymKey(mEncKey);
+ if (mMacKey) PK11_FreeSymKey(mMacKey);
+
+ mEncKey = 0;
+ mMacKey = 0;
+
+ return 0;
+ }
+
+ int
+ Server::CompareKeys(Server *peer)
+ {
+ int rv;
+ SECItem *macKey1 = 0;
+ SECItem *macKey2 = 0;
+ SECItem *encKey1 = 0;
+ SECItem *encKey2 = 0;
+
+ // Export each of the keys in raw form
+ rv = rawExportKey(mMacKey, &macKey1);
+ if (rv) goto done;
+
+ rv = rawExportKey(peer->mMacKey, &macKey2);
+ if (rv) goto done;
+
+ rv = rawExportKey(mEncKey, &encKey1);
+ if (rv) goto done;
+
+ rv = rawExportKey(peer->mEncKey, &encKey2);
+ if (rv) goto done;
+
+ if (!SECITEM_ItemsAreEqual(macKey1, macKey2)) { rv = 1; goto done; }
+ if (!SECITEM_ItemsAreEqual(encKey1, encKey2)) { rv = 1; goto done; }
+
+ done:
+ if (macKey1) SECITEM_ZfreeItem(macKey1, PR_TRUE);
+ if (macKey2) SECITEM_ZfreeItem(macKey2, PR_TRUE);
+ if (encKey1) SECITEM_ZfreeItem(encKey1, PR_TRUE);
+ if (encKey2) SECITEM_ZfreeItem(encKey2, PR_TRUE);
+
+ return rv;
+ }
+
+ // Private helper, retrieves the private key for the server
+ // from the database. Free the key using SECKEY_DestroyPrivateKey
+ int
+ Server::getPrivateKey(SECKEYPrivateKey **prvKey)
+ {
+ int rv = 0;
+ PK11SlotInfo *slot = 0;
+ SECKEYPrivateKeyList *list = 0;
+ SECKEYPrivateKeyListNode *n;
+ char *nickname;
+
+ slot = PK11_GetInternalKeySlot();
+ if (!slot) goto done;
+
+ // ListPrivKeysInSlot looks like it should check the
+ // nickname and only return keys that match. However,
+ // that doesn't seem to work at the moment.
+ // BUG: XXXXX
+ list = PK11_ListPrivKeysInSlot(slot, mServerName, 0);
+ cout << "getPrivateKey: list = " << list << endl;
+ if (!list) { rv = 1; goto done; }
+
+ for(n = PRIVKEY_LIST_HEAD(list);
+ !PRIVKEY_LIST_END(n, list);
+ n = PRIVKEY_LIST_NEXT(n))
+ {
+ nickname = PK11_GetPrivateKeyNickname(n->key);
+ if (PL_strcmp(nickname, mServerName) == 0) break;
+ }
+ if (PRIVKEY_LIST_END(n, list)) { rv = 1; goto done; }
+
+ *prvKey = SECKEY_CopyPrivateKey(n->key);
+
+ done:
+ if (list) SECKEY_DestroyPrivateKeyList(list);
+
+ return rv;
+ }
+
+ int
+ Server::getPublicKey(SECKEYPublicKey **pubKey)
+ {
+ int rv;
+ SECKEYPrivateKey *prvKey = 0;
+
+ rv = getPrivateKey(&prvKey);
+ if (rv) goto done;
+
+ *pubKey = SECKEY_ConvertToPublicKey(prvKey);
+ if (!*pubKey) { rv = 1; goto done; }
+
+ done:
+ if (prvKey) SECKEY_DestroyPrivateKey(prvKey);
+
+ return rv;
+ }
+
+ int
+ Server::wrapKey(PK11SymKey *key, SECKEYPublicKey *pubKey, SECItem **ret)
+ {
+ int rv = 0;
+ SECItem *data;
+ SECStatus s;
+
+ data = (SECItem *)PORT_ZAlloc(sizeof(SECItem));
+ if (!data) { rv = 1; goto done; }
+
+ // Allocate space for output of wrap
+ data->len = SECKEY_PublicKeyStrength(pubKey);
+ data->data = new unsigned char[data->len];
+ if (!data->data) { rv = 1; goto done; }
+
+ s = PK11_PubWrapSymKey(CKM_RSA_PKCS, pubKey, key, data);
+ if (s != SECSuccess) { rv = 1; goto done; }
+
+ *ret = data;
+ data = 0;
+
+ done:
+ if (data) SECITEM_FreeItem(data, PR_TRUE);
+
+ return rv;
+ }
+
+ // Example of how to do a raw export (no wrapping of a key)
+ // This should not be used. Use the RSA-based wrapping
+ // methods instead.
+ int
+ Server::rawExportKey(PK11SymKey *key, SECItem **res)
+ {
+ int rv = 0;
+ SECItem *data;
+ SECStatus s;
+
+ s = PK11_ExtractKeyValue(key);
+ if (s != SECSuccess) { rv = 1; goto done; }
+
+ data = PK11_GetKeyData(key);
+
+ *res = SECITEM_DupItem(data);
+ if (!*res) { rv = 1; goto done; }
+
+ done:
+ return rv;
+ }
+
+ // Initialize the NSS library. Normally this
+ // would be done as part of each server's startup.
+ // However, this example uses the same databases
+ // to store keys for server in the "cluster" so
+ // it is done once.
+ int
+ InitNSS()
+ {
+ int rv = 0;
+ SECStatus s;
+
+ s = NSS_InitReadWrite(".");
+ if (s != SECSuccess) rv = 1; // Error
+
+ // For this example, we don't use database passwords
+ PK11_InitPin(PK11_GetInternalKeySlot(), "", "");
+
+ return rv;
+ }
+
+ int
+ main(int argc, char *argv[])
+ {
+ int rv;
+ Server *server1 = 0;
+ Server *server2 = 0;
+
+ // Initialize NSS
+ rv = InitNSS();
+ if (rv) { cout << "InitNSS failed" << endl; goto done; }
+
+ // Create the first "server"
+ server1 = new Server("Server1");
+ if (!server1 || server1->Init())
+ {
+ cout << "Server1 could not be created" << endl;
+ rv = 1;
+ goto done;
+ }
+
+ // Generate encryption and mac keys. These keys will
+ // be used by all the servers in the cluster.
+ rv = server1->GenerateKeys();
+ if (rv) { cout << "GenerateKeys failed" << endl; goto done; }
+
+ // Now that everything is ready, start server1. This loads
+ // the encryption and MAC keys from the "files"
+ rv = server1->Start();
+ if (rv) { cout << "Cannot start server 1" << endl; goto done; }
+
+ // Create a second server in the cluster. We will need
+ // to transfer the keys from the first server to this
+ // one
+ server2 = new Server("Server2");
+ if (!server2 || server2->Init())
+ {
+ cout << "Server2 could not be created" << endl;
+ rv = 1; // Error
+ goto done;
+ }
+
+ // Transfer the keys from server1
+ {
+ SECItem *wrappedEncKey = 0;
+ SECItem *wrappedMacKey = 0;
+ SECItem *pubKeyData = 0;
+
+ // Get the public key for server 2 so that it can
+ // be sent to server 1
+ rv = server2->ExportPublicKey(&pubKeyData);
+ if (rv) { cout << "ExportPublicKey failed" << endl; goto trans_done; }
+
+ // Send the public key to server 1 and get back the
+ // wrapped key values
+ rv = server1->ExportKeys(pubKeyData, &wrappedEncKey, &wrappedMacKey);
+ if (rv) { cout << "ExportKeys failed" << endl; goto trans_done; }
+
+ // Print - for information
+ cout << "Wrapped Encryption Key" << endl;
+ printBuffer(wrappedEncKey->data, wrappedEncKey->len);
+ cout << "Wrapped MAC Key" << endl;
+ printBuffer(wrappedMacKey->data, wrappedMacKey->len);
+
+ // Import the keys into server 2 - this just puts the wrapped
+ // values into the "files"
+ rv = server2->ImportKeys(wrappedEncKey, wrappedMacKey);
+ if (rv) { cout << "ImportKeys failed" << endl; goto trans_done; }
+
+ trans_done:
+ if (wrappedEncKey) SECITEM_FreeItem(wrappedEncKey, PR_TRUE);
+ if (wrappedMacKey) SECITEM_FreeItem(wrappedMacKey, PR_TRUE);
+ if (pubKeyData) SECITEM_FreeItem(pubKeyData, PR_TRUE);
+ }
+ if (rv) goto done;
+
+ // Start server 2 - this unwraps the encryption and MAC keys
+ // so that they can be used
+ rv = server2->Start();
+ if (rv) { cout << "Cannot start server 2" << endl; goto done; }
+
+ // List keys in the token - informational
+ {
+ PK11SlotInfo *slot = 0;
+ SECKEYPrivateKeyList *list = 0;
+ SECKEYPrivateKeyListNode *n;
+
+ slot = PK11_GetInternalKeySlot();
+ if (!slot) goto list_done;
+
+ cout << "List Private Keys" << endl;
+
+ list = PK11_ListPrivKeysInSlot(slot, 0, 0);
+ if (!list) goto list_done;
+
+ for(n = PRIVKEY_LIST_HEAD(list);
+ !PRIVKEY_LIST_END(n, list);
+ n = PRIVKEY_LIST_NEXT(n))
+ {
+ char *name;
+
+ name = PK11_GetPrivateKeyNickname(n->key);
+ cout << "Key: " << name << endl;
+ }
+ list_done:
+ if (slot) PK11_FreeSlot(slot);
+ if (list) SECKEY_DestroyPrivateKeyList(list);
+
+ cout << "Done" << endl;
+ }
+
+ // Let's see if the keys are the same
+ rv = server1->CompareKeys(server2);
+ if (rv) { cout << "Key Comparison failed" << endl; }
+
+ server1->Shutdown();
+ server2->Shutdown();
+
+ done:
+ if (server1) delete server1;
+ if (server2) delete server2;
+
+ NSS_Shutdown();
+
+ return rv;
+ } \ No newline at end of file
diff --git a/security/nss/doc/rst/legacy/nss_sample_code/nss_sample_code_sample2/index.rst b/security/nss/doc/rst/legacy/nss_sample_code/nss_sample_code_sample2/index.rst
new file mode 100644
index 0000000000..76f6c21d8f
--- /dev/null
+++ b/security/nss/doc/rst/legacy/nss_sample_code/nss_sample_code_sample2/index.rst
@@ -0,0 +1,166 @@
+.. _mozilla_projects_nss_nss_sample_code_nss_sample_code_sample2:
+
+NSS Sample Code sample2
+=======================
+
+.. _nss_sample_code_2_symmetric_encryption:
+
+`NSS Sample Code 2: Symmetric Encryption <#nss_sample_code_2_symmetric_encryption>`__
+-------------------------------------------------------------------------------------
+
+.. container::
+
+ .. code::
+
+ /* Example code to illustrate DES enccryption/decryption using NSS.
+ * The example skips the details of obtaining the Key & IV to use, and
+ * just uses a hardcoded Key & IV.
+ * Note: IV is only needed if Cipher Blocking Chaining (CBC) mode of encryption
+ * is used
+ *
+ * The recommended approach is to store and transport WRAPPED (encrypted)
+ * DES Keys (IVs can be in the clear). However, it is a common (and dangerous)
+ * practice to use raw DES Keys. This example shows the use of a RAW key.
+ */
+
+
+ #include "nss.h"
+ #include "pk11pub.h"
+
+ /* example Key & IV */
+ unsigned char gKey[] = {0xe8, 0xa7, 0x7c, 0xe2, 0x05, 0x63, 0x6a, 0x31};
+ unsigned char gIV[] = {0xe4, 0xbb, 0x3b, 0xd3, 0xc3, 0x71, 0x2e, 0x58};
+
+ int main(int argc, char **argv)
+ {
+ CK_MECHANISM_TYPE cipherMech;
+ PK11SlotInfo* slot = NULL;
+ PK11SymKey* SymKey = NULL;
+ SECItem* SecParam = NULL;
+ PK11Context* EncContext = NULL;
+ SECItem keyItem, ivItem;
+ SECStatus rv, rv1, rv2;
+ unsigned char data[1024], buf1[1024], buf2[1024];
+ int i, result_len, tmp1_outlen, tmp2_outlen;
+
+ /* Initialize NSS
+ * If your application code has already initialized NSS, you can skip it
+ * here.
+ * This code uses the simplest of the Init functions, which does not
+ * require a NSS database to exist
+ */
+ rv = NSS_NoDB_Init(".");
+ if (rv != SECSuccess)
+ {
+ fprintf(stderr, "NSS initialization failed (err %d)\n",
+ PR_GetError());
+ goto out;
+ }
+
+ /* choose mechanism: CKM_DES_CBC_PAD, CKM_DES3_ECB, CKM_DES3_CBC.....
+ * Note that some mechanisms (*_PAD) imply the padding is handled for you
+ * by NSS. If you choose something else, then data padding is the
+ * application's responsibility
+ */
+ cipherMech = CKM_DES_CBC_PAD;
+ slot = PK11_GetBestSlot(cipherMech, NULL);
+ /* slot = PK11_GetInternalKeySlot(); is a simpler alternative but in
+ * theory, it *may not* return the optimal slot for the operation. For
+ * DES ops, Internal slot is typically the best slot
+ */
+ if (slot == NULL)
+ {
+ fprintf(stderr, "Unable to find security device (err %d)\n",
+ PR_GetError());
+ goto out;
+ }
+
+ /* NSS passes blobs around as SECItems. These contain a pointer to
+ * data and a length. Turn the raw key into a SECItem. */
+ keyItem.type = siBuffer;
+ keyItem.data = gKey;
+ keyItem.len = sizeof(gKey);
+
+ /* Turn the raw key into a key object. We use PK11_OriginUnwrap
+ * to indicate the key was unwrapped - which is what should be done
+ * normally anyway - using raw keys isn't a good idea */
+ SymKey = PK11_ImportSymKey(slot, cipherMech, PK11_OriginUnwrap, CKA_ENCRYPT,
+ &keyItem, NULL);
+ if (SymKey == NULL)
+ {
+ fprintf(stderr, "Failure to import key into NSS (err %d)\n",
+ PR_GetError());
+ goto out;
+ }
+
+ /* set up the PKCS11 encryption parameters.
+ * when not using CBC mode, ivItem.data and ivItem.len can be 0, or you
+ * can simply pass NULL for the iv parameter in PK11_ParamFromIV func
+ */
+ ivItem.type = siBuffer;
+ ivItem.data = gIV;
+ ivItem.len = sizeof(gIV);
+ SecParam = PK11_ParamFromIV(cipherMech, &ivItem);
+ if (SecParam == NULL)
+ {
+ fprintf(stderr, "Failure to set up PKCS11 param (err %d)\n",
+ PR_GetError());
+ goto out;
+ }
+
+ /* sample data we'll encrypt and decrypt */
+ strcpy(data, "Encrypt me!");
+ fprintf(stderr, "Clear Data: %s\n", data);
+
+ /* ========================= START SECTION ============================= */
+ /* If using the same key and iv over and over, stuff before this */
+ /* section and after this section needs to be done only ONCE */
+
+ /* ENCRYPT data into buf1. buf1 len must be atleast (data len + 8) */
+ tmp1_outlen = tmp2_outlen = 0;
+
+ /* Create cipher context */
+ EncContext = PK11_CreateContextBySymKey(cipherMech, CKA_ENCRYPT,
+ SymKey, SecParam);
+ rv1 = PK11_CipherOp(EncContext, buf1, &tmp1_outlen, sizeof(buf1),
+ data, strlen(data)+1);
+ rv2 = PK11_DigestFinal(EncContext, buf1+tmp1_outlen, &tmp2_outlen,
+ sizeof(buf1)-tmp1_outlen);
+ PK11_DestroyContext(EncContext, PR_TRUE);
+ result_len = tmp1_outlen + tmp2_outlen;
+ if (rv1 != SECSuccess || rv2 != SECSuccess)
+ goto out;
+
+ fprintf(stderr, "Encrypted Data: ");
+ for (i=0; i<result_len; i++)
+ fprintf(stderr, "%02x ", buf1[i]);
+ fprintf(stderr, "\n");
+
+
+ /* DECRYPT buf1 into buf2. buf2 len must be atleast buf1 len */
+ tmp1_outlen = tmp2_outlen = 0;
+
+ /* Create cipher context */
+ EncContext = PK11_CreateContextBySymKey(cipherMech, CKA_DECRYPT,
+ SymKey, SecParam);
+ rv1 = PK11_CipherOp(EncContext, buf2, &tmp1_outlen, sizeof(buf2),
+ buf1, result_len);
+ rv2 = PK11_DigestFinal(EncContext, buf2+tmp1_outlen, &tmp2_outlen,
+ result_len-tmp1_outlen);
+ PK11_DestroyContext(EncContext, PR_TRUE);
+ result_len = tmp1_outlen + tmp2_outlen;
+ if (rv1 != SECSuccess || rv2 != SECSuccess)
+ goto out;
+
+ fprintf(stderr, "Decrypted Data: %s\n", buf2);
+
+ /* =========================== END SECTION ============================= */
+
+
+ out:
+ if (SymKey)
+ PK11_FreeSymKey(SymKey);
+ if (SecParam)
+ SECITEM_FreeItem(SecParam, PR_TRUE);
+
+ } \ No newline at end of file
diff --git a/security/nss/doc/rst/legacy/nss_sample_code/nss_sample_code_sample3/index.rst b/security/nss/doc/rst/legacy/nss_sample_code/nss_sample_code_sample3/index.rst
new file mode 100644
index 0000000000..51f37f6619
--- /dev/null
+++ b/security/nss/doc/rst/legacy/nss_sample_code/nss_sample_code_sample3/index.rst
@@ -0,0 +1,169 @@
+.. _mozilla_projects_nss_nss_sample_code_nss_sample_code_sample3:
+
+NSS Sample Code sample3
+=======================
+
+.. _sample_code_3_hashing_mac:
+
+`Sample Code 3: Hashing, MAC <#sample_code_3_hashing_mac>`__
+------------------------------------------------------------
+
+.. container::
+
+ .. code::
+
+ /*
+ * Demonstration program for hashing and MACs
+ */
+
+ #include <iostream.h>
+
+ #include "pk11pub.h"
+ #include "nss.h"
+
+ static void
+ printDigest(unsigned char *digest, unsigned int len)
+ {
+ int i;
+
+ cout << "length: " << len << endl;
+ for(i = 0;i < len;i++) printf("%02x ", digest[i]);
+ cout << endl;
+ }
+
+ /*
+ * main
+ */
+ int
+ main(int argc, const char *argv[])
+ {
+ int status = 0;
+ PK11SlotInfo *slot = 0;
+ PK11SymKey *key = 0;
+ PK11Context *context = 0;
+ unsigned char data[80];
+ unsigned char digest[20]; /*Is there a way to tell how large the output is?*/
+ unsigned int len;
+ SECStatus s;
+
+ /* Initialize NSS
+ * If your application code has already initialized NSS, you can skip it
+ * here.
+ * This code uses the simplest of the Init functions, which does not
+ * require a NSS database to exist
+ */
+ NSS_NoDB_Init(".");
+
+ /* Get a slot to use for the crypto operations */
+ slot = PK11_GetInternalKeySlot();
+ if (!slot)
+ {
+ cout << "GetInternalKeySlot failed" << endl;
+ status = 1;
+ goto done;
+ }
+
+ /*
+ * Part 1 - Simple hashing
+ */
+ cout << "Part 1 -- Simple hashing" << endl;
+
+ /* Initialize data */
+ memset(data, 0xbc, sizeof data);
+
+ /* Create a context for hashing (digesting) */
+ context = PK11_CreateDigestContext(SEC_OID_MD5);
+ if (!context) { cout << "CreateDigestContext failed" << endl; goto done; }
+
+ s = PK11_DigestBegin(context);
+ if (s != SECSuccess) { cout << "DigestBegin failed" << endl; goto done; }
+
+ s = PK11_DigestOp(context, data, sizeof data);
+ if (s != SECSuccess) { cout << "DigestUpdate failed" << endl; goto done; }
+
+ s = PK11_DigestFinal(context, digest, &len, sizeof digest);
+ if (s != SECSuccess) { cout << "DigestFinal failed" << endl; goto done; }
+
+ /* Print digest */
+ printDigest(digest, len);
+
+ PK11_DestroyContext(context, PR_TRUE);
+ context = 0;
+
+ /*
+ * Part 2 - Hashing with included secret key
+ */
+ cout << "Part 2 -- Hashing with included secret key" << endl;
+
+ /* Initialize data */
+ memset(data, 0xbc, sizeof data);
+
+ /* Create a Key */
+ key = PK11_KeyGen(slot, CKM_GENERIC_SECRET_KEY_GEN, 0, 128, 0);
+ if (!key) { cout << "Create key failed" << endl; goto done; }
+
+ cout << (void *)key << endl;
+
+ /* Create parameters for crypto context */
+ /* NOTE: params must be provided, but may be empty */
+ SECItem noParams;
+ noParams.type = siBuffer;
+ noParams.data = 0;
+ noParams.len = 0;
+
+ /* Create context using the same slot as the key */
+ // context = PK11_CreateDigestContext(SEC_OID_MD5);
+ context = PK11_CreateContextBySymKey(CKM_MD5, CKA_DIGEST, key, &noParams);
+ if (!context) { cout << "CreateDigestContext failed" << endl; goto done; }
+
+ s = PK11_DigestBegin(context);
+ if (s != SECSuccess) { cout << "DigestBegin failed" << endl; goto done; }
+
+ s = PK11_DigestKey(context, key);
+ if (s != SECSuccess) { cout << "DigestKey failed" << endl; goto done; }
+
+ s = PK11_DigestOp(context, data, sizeof data);
+ if (s != SECSuccess) { cout << "DigestUpdate failed" << endl; goto done; }
+
+ s = PK11_DigestFinal(context, digest, &len, sizeof digest);
+ if (s != SECSuccess) { cout << "DigestFinal failed" << endl; goto done; }
+
+ /* Print digest */
+ printDigest(digest, len);
+
+ PK11_DestroyContext(context, PR_TRUE);
+ context = 0;
+
+ /*
+ * Part 3 - MAC (with secret key)
+ */
+ cout << "Part 3 -- MAC (with secret key)" << endl;
+
+ /* Initialize data */
+ memset(data, 0xbc, sizeof data);
+
+ context = PK11_CreateContextBySymKey(CKM_MD5_HMAC, CKA_SIGN, key, &noParams);
+ if (!context) { cout << "CreateContextBySymKey failed" << endl; goto done; }
+
+ s = PK11_DigestBegin(context);
+ if (s != SECSuccess) { cout << "DigestBegin failed" << endl; goto done; }
+
+ s = PK11_DigestOp(context, data, sizeof data);
+ if (s != SECSuccess) { cout << "DigestOp failed" << endl; goto done; }
+
+ s = PK11_DigestFinal(context, digest, &len, sizeof digest);
+ if (s != SECSuccess) { cout << "DigestFinal failed" << endl; goto done; }
+
+ /* Print digest */
+ printDigest(digest, len);
+
+ PK11_DestroyContext(context, PR_TRUE);
+ context = 0;
+
+ done:
+ if (context) PK11_DestroyContext(context, PR_TRUE); /* freeit ?? */
+ if (key) PK11_FreeSymKey(key);
+ if (slot) PK11_FreeSlot(slot);
+
+ return status;
+ } \ No newline at end of file
diff --git a/security/nss/doc/rst/legacy/nss_sample_code/nss_sample_code_sample4/index.rst b/security/nss/doc/rst/legacy/nss_sample_code/nss_sample_code_sample4/index.rst
new file mode 100644
index 0000000000..1d5cba11ce
--- /dev/null
+++ b/security/nss/doc/rst/legacy/nss_sample_code/nss_sample_code_sample4/index.rst
@@ -0,0 +1,158 @@
+.. _mozilla_projects_nss_nss_sample_code_nss_sample_code_sample4:
+
+NSS Sample Code sample4
+=======================
+
+.. _nss_sample_code_4_pki_encryption:
+
+`NSS Sample Code 4: PKI Encryption <#nss_sample_code_4_pki_encryption>`__
+-------------------------------------------------------------------------
+
+.. container::
+
+ .. code::
+
+ /* Example code to illustrate PKI crypto ops (encrypt with public key,
+ * decrypt with private key)
+ *
+ * Code assumes that you have set up a NSS database with a certificate
+ * and a private key. The db password should be "test" and the cert
+ * nickname should be "TestCA"
+ * Here is one way of doing it:
+ * # create CA cert db, if -f not provided, prompts for passwd
+ * $ certutil -N -d .
+ * # create CA cert, self-signed, generates key-pair, prompts for key
+ * # type, cert type etc
+ * # answers for prompts: 5,9,n,y,-1,n,5,6,7,9,n
+ * $ certutil -S -s "CN=Test CA, O=BOGUS Inc, L=Mtn View, ST=CA, C=US" \
+ * -n TestCA -t CTu,CTu,CTu -v 60 -x -d . -1 -2 -5
+ *
+ * There are many ways to setup a public/private key to use - this
+ * example shows one of them.
+ *
+ * This example does not do any padding. It simply encrypts/decrypts a block
+ * of length equal to modulus length of the public/private key.
+ */
+
+
+ #include "nss.h"
+ #include "pk11pub.h"
+
+
+ /* this callback is responsible for returning the password to the NSS
+ * key database. for example purposes, this function hardcodes the password.
+ * In a real app, this function should obtain the password using secure means
+ * such as prompting an operator, or retrieving it over a secure communication
+ * channel
+ */
+ char *passwdcb(PK11SlotInfo *info, PRBool retry, void *arg);
+
+
+ int main(int argc, char **argv)
+ {
+ SECStatus rv;
+ CERTCertificate *cert = NULL;
+ SECKEYPublicKey *pubkey = NULL;
+ SECKEYPrivateKey *pvtkey = NULL;
+ int modulus_len, i, outlen;
+ char *buf1 = NULL;
+ char *buf2 = NULL;
+
+ /* Initialize NSS */
+ PK11_SetPasswordFunc(passwdcb);
+ rv = NSS_Init(".");
+ if (rv != SECSuccess)
+ {
+ fprintf(stderr, "NSS initialization failed (err %d)\n",
+ PR_GetError());
+ goto cleanup;
+ }
+
+ cert = PK11_FindCertFromNickname("TestCA", NULL);
+ if (cert == NULL)
+ {
+ fprintf(stderr, "Couldn't find cert TestCA in NSS db (err %d)\n",
+ PR_GetError());
+ goto cleanup;
+ }
+
+ pubkey = CERT_ExtractPublicKey(cert);
+ if (pubkey == NULL)
+ {
+ fprintf(stderr, "Couldn't extract public key from cert TestCA (err %d)\n",
+ PR_GetError());
+ goto cleanup;
+ }
+
+ modulus_len = SECKEY_PublicKeyStrength(pubkey);
+ fprintf(stderr, "Public Key Modulus %d bytes\n", modulus_len);
+ buf1 = (char *)malloc(modulus_len);
+ buf2 = (char *)malloc(modulus_len);
+
+ /* initialize buf1 */
+ for (i=0;i<modulus_len;i++)
+ {
+ buf1[i]= (i %26) + 'A';
+ }
+ buf1[modulus_len-1] = '\0';
+ fprintf(stderr, "Buffer being encrypted = \n%s\n", buf1);
+
+ /* encrypt buf1, result will be in buf2 */
+ rv = PK11_PubEncryptRaw(pubkey, buf2, buf1, modulus_len, NULL);
+ if (rv != SECSuccess)
+ {
+ fprintf(stderr, "Encrypt with Public Key failed (err %d)\n",
+ PR_GetError());
+ goto cleanup;
+ }
+
+ pvtkey = PK11_FindKeyByAnyCert(cert, NULL);
+ if (pvtkey == NULL)
+ {
+ fprintf(stderr, "Couldn't find private key for cert TestCA (err %d)\n",
+ PR_GetError());
+ goto cleanup;
+ }
+
+ /* clear buf1 */
+ for (i=0;i<modulus_len;i++)
+ {
+ buf1[i]= '\0';
+ }
+
+ /* decrypt buf2, result will be in buf1 */
+ rv = PK11_PubDecryptRaw(pvtkey, buf1, &outlen, modulus_len, buf2,
+ modulus_len);
+ if (rv != SECSuccess)
+ {
+ fprintf(stderr, "Decrypt with Private Key failed (err %d)\n",
+ PR_GetError());
+ goto cleanup;
+ }
+
+ fprintf(stderr, "Result of decryption, outlen = %d\n", outlen);
+ fprintf(stderr, "Result of decryption, buf = \n%s\n", buf1);
+
+ exit(0);
+
+ cleanup:
+ if (cert)
+ CERT_DestroyCertificate(cert);
+ if (pubkey)
+ SECKEY_DestroyPublicKey(pubkey);
+ if (pvtkey)
+ SECKEY_DestroyPrivateKey(pvtkey);
+ if (buf1)
+ free(buf1);
+ if (buf2)
+ free(buf2);
+ exit(1);
+ }
+
+ char *passwdcb(PK11SlotInfo *info, PRBool retry, void *arg)
+ {
+ if (!retry)
+ return PL_strdup("test");
+ else
+ return NULL;
+ } \ No newline at end of file
diff --git a/security/nss/doc/rst/legacy/nss_sample_code/nss_sample_code_sample5/index.rst b/security/nss/doc/rst/legacy/nss_sample_code/nss_sample_code_sample5/index.rst
new file mode 100644
index 0000000000..f4e8235ad5
--- /dev/null
+++ b/security/nss/doc/rst/legacy/nss_sample_code/nss_sample_code_sample5/index.rst
@@ -0,0 +1,174 @@
+.. _mozilla_projects_nss_nss_sample_code_nss_sample_code_sample5:
+
+NSS Sample Code sample5
+=======================
+
+.. _nss_sample_code_5_pki_encryption_with_a_raw_public_private_key_in_der_format:
+
+`NSS Sample Code 5: PKI Encryption with a raw public & private key in DER format <#nss_sample_code_5_pki_encryption_with_a_raw_public_private_key_in_der_format>`__
+-------------------------------------------------------------------------------------------------------------------------------------------------------------------
+
+.. container::
+
+ .. code::
+
+ /* Example code to illustrate PKI crypto ops (encrypt with public key,
+ * decrypt with private key)
+ *
+ * No NSS db needed. The Public Key & Private Key to use are
+ * sourced from a base64-encoded DER SubjectPublicKeyInfo structure,
+ * and a base64-encoded DER PrivateKeyInfo structure.
+ *
+ * There is no attempt to link the public & private key together
+ *
+ * This example does not do any padding. It simply encrypts/decrypts a block
+ * of length equal to modulus length of the public/private key.
+ */
+
+
+ #include "nss.h"
+ #include "pk11pub.h"
+
+ #define BASE64_ENCODED_SUBJECTPUBLICKEYINFO "MFwwDQYJKoZIhvcNAQEBBQADSwAwSAJBAL3F6TIc3JEYsugo+a2fPU3W+Epv/FeIX21DC86WYnpFtW4srFtz2oNUzyLUzDHZdb+k//8dcT3IAOzUUi3R2eMCAwEAAQ=="
+
+ #define BASE64_ENCODED_PRIVATEKEYINFO "MIIBVQIBADANBgkqhkiG9w0BAQEFAASCAT8wggE7AgEAAkEAvcXpMhzckRiy6Cj5rZ89Tdb4Sm/8V4hfbUMLzpZiekW1biysW3Pag1TPItTMMdl1v6T//x1xPcgA7NRSLdHZ4wIDAQABAkEAjh8+4qncwcmGivnM6ytbpQT+k/jEOeXG2bQhjojvnXN3FazGCEFXvpuIBcJVfaIJS9YBCMOzzrAtO0+k2hWnOQIhAOC4NVbo8FQhZS4yXM1M86kMl47FA9ui//OUfbhlAdw1AiEA2DBmIXnsboKB+OHver69p0gNeWlvcJc9bjDVfdLVsLcCIQCPtV3vGYJv2vdwxqZQaHC+YB4gIGAqOqBCbmjD3lyFLQIgA+VTYdUNoqwtZWvE4gRf7IzK2V5CCNhg3gR5RGwxN58CIGCcafoRrUKsM66ISg0ITI04G9V/w+wMx91wjEEB+QBz"
+
+
+ int main(int argc, char **argv)
+ {
+ SECStatus rv;
+ CERTCertificate *cert = NULL;
+ SECKEYPublicKey *pubkey = NULL;
+ CERTSubjectPublicKeyInfo *spki = NULL;
+ SECKEYPrivateKey *pvtkey = NULL;
+ int modulus_len, i, outlen;
+ char *buf1 = NULL;
+ char *buf2 = NULL;
+ char *pubkstr = BASE64_ENCODED_SUBJECTPUBLICKEYINFO;
+ char *pvtkstr = BASE64_ENCODED_PRIVATEKEYINFO;
+ SECItem der;
+ SECItem nickname;
+ PK11SlotInfo *slot = NULL;
+
+ /* Initialize NSS
+ * You need to explicitly authenticate to the internal token if you use
+ * NSS_Init insteadf of NSS_NoDB_Init
+ * Invoke this after getting the internal token handle
+ * PK11_Authenticate(slot, PR_FALSE, NULL);
+ */
+ rv = NSS_NoDB_Init(".");
+ if (rv != SECSuccess)
+ {
+ fprintf(stderr, "NSS initialization failed (err %d)\n",
+ PR_GetError());
+ goto cleanup;
+ }
+
+ /* get internal slot */
+ slot = PK11_GetInternalKeySlot();
+ if (slot == NULL)
+ {
+ fprintf(stderr, "Couldn't find slot (err %d)\n", PR_GetError());
+ goto cleanup;
+ }
+
+ rv = ATOB_ConvertAsciiToItem(&der, pubkstr);
+ if (rv!= SECSuccess)
+ {
+ fprintf(stderr, "ATOB_ConvertAsciiToItem failed %d\n", PR_GetError());
+ goto cleanup;
+ }
+ spki = SECKEY_DecodeDERSubjectPublicKeyInfo(&der);
+ SECITEM_FreeItem(&der, PR_FALSE);
+ pubkey = SECKEY_ExtractPublicKey(spki);
+
+ if (pubkey == NULL)
+ {
+ fprintf(stderr, "Couldn't extract public key (err %d)\n", PR_GetError());
+ goto cleanup;
+ }
+
+ modulus_len = SECKEY_PublicKeyStrength(pubkey);
+ fprintf(stderr, "Public Key Modulus %d bytes\n", modulus_len);
+ buf1 = (char *)malloc(modulus_len);
+ buf2 = (char *)malloc(modulus_len);
+
+ /* initialize buf1 */
+ for (i=0;i<modulus_len;i++)
+ {
+ buf1[i]= (i %26) + 'A';
+ }
+ buf1[modulus_len-1] = '\0';
+ fprintf(stderr, "Buffer being encrypted = \n%s\n", buf1);
+
+ /* encrypt buf1, result will be in buf2 */
+ rv = PK11_PubEncryptRaw(pubkey, buf2, buf1, modulus_len, NULL);
+ if (rv != SECSuccess)
+ {
+ fprintf(stderr, "Encrypt with Public Key failed (err %d)\n",
+ PR_GetError());
+ goto cleanup;
+ }
+
+ nickname.type = siBuffer;
+ nickname.data = "pvtkeynickname";
+ nickname.len = strlen("pvtkeynickname");
+ rv = ATOB_ConvertAsciiToItem(&der, pvtkstr);
+ if (rv!= SECSuccess)
+ {
+ fprintf(stderr, "ATOB_ConvertAsciiToItem failed %d\n", PR_GetError());
+ goto cleanup;
+ }
+
+ /* KU_ALL includes a lot of different key usages, KU_DATA_ENCIPHERMENT
+ * is enough for just RSA encryption.
+ * publicValue arg (4th) can be NULL for RSA key - I think it is even
+ * ignored
+ */
+ PK11_ImportDERPrivateKeyInfoAndReturnKey(slot, &der, NULL,
+ NULL, PR_FALSE, PR_TRUE,
+ KU_ALL, &pvtkey, NULL);
+ SECITEM_FreeItem(&der, PR_FALSE);
+
+ if (pvtkey == NULL)
+ {
+ fprintf(stderr, "Couldn't extract private key (err %d)\n", PR_GetError());
+ goto cleanup;
+ }
+
+ /* clear buf1 */
+ for (i=0;i<modulus_len;i++)
+ {
+ buf1[i]= '\0';
+ }
+
+ /* decrypt buf2, result will be in buf1 */
+ rv = PK11_PubDecryptRaw(pvtkey, buf1, &outlen, modulus_len, buf2,
+ modulus_len);
+ if (rv != SECSuccess)
+ {
+ fprintf(stderr, "Decrypt with Private Key failed (err %d)\n",
+ PR_GetError());
+ goto cleanup;
+ }
+
+ fprintf(stderr, "Result of decryption, outlen = %d\n", outlen);
+ fprintf(stderr, "Result of decryption, buf = \n%s\n", buf1);
+
+ cleanup:
+ if (cert)
+ CERT_DestroyCertificate(cert);
+ if (pubkey)
+ SECKEY_DestroyPublicKey(pubkey);
+ if (pvtkey)
+ SECKEY_DestroyPrivateKey(pvtkey);
+ if (spki)
+ SECKEY_DestroySubjectPublicKeyInfo(spki);
+ if (slot)
+ PK11_FreeSlot(slot);
+ if (buf1)
+ free(buf1);
+ if (buf2)
+ free(buf2);
+ exit(1);
+ } \ No newline at end of file
diff --git a/security/nss/doc/rst/legacy/nss_sample_code/nss_sample_code_sample6/index.rst b/security/nss/doc/rst/legacy/nss_sample_code/nss_sample_code_sample6/index.rst
new file mode 100644
index 0000000000..b194873bc4
--- /dev/null
+++ b/security/nss/doc/rst/legacy/nss_sample_code/nss_sample_code_sample6/index.rst
@@ -0,0 +1,153 @@
+.. _mozilla_projects_nss_nss_sample_code_nss_sample_code_sample6:
+
+NSS Sample Code sample6
+=======================
+
+.. _nss_sample_code_6_persistent_symmetric_keys_in_nss_database:
+
+`NSS Sample Code 6: Persistent Symmetric Keys in NSS database <#nss_sample_code_6_persistent_symmetric_keys_in_nss_database>`__
+-------------------------------------------------------------------------------------------------------------------------------
+
+.. container::
+
+ .. code::
+
+ /* Example code to illustrate generation of a secret symmetric key ring
+ * that PERSISTS in the NSS database. The symmetric keys can then be used
+ * without ever exposing them in the clear.
+ *
+ * To encrypt, you need the id of the key to use.
+ * To decrypt, you need the ciphertext and the id of the key that was used
+ * to encrypt
+ *
+ * Before running this example, create the NSS database
+ * certutil -N -d .
+ * (enter "test" when prompted for password)
+ */
+
+
+ #include "nss.h"
+ #include "pk11pub.h"
+
+ /* the key id can be any sequence of bytes. this example happens to use an
+ * integer */
+ void genkey(int id);
+
+ /* this callback is responsible for returning the password to the NSS
+ * key database. for example purposes, this function hardcodes the password.
+ * In a real app, this function should obtain the password using secure means
+ * such as prompting an operator, or retrieving it over a secure communication
+ * channel
+ */
+ char *passwdcb(PK11SlotInfo *info, PRBool retry, void *arg);
+
+
+ int main(int argc, char **argv)
+ {
+ SECStatus rv;
+
+ /* Initialize NSS */
+ PK11_SetPasswordFunc(passwdcb);
+
+ /* The NSS db must be initialized read-write since we'll be creating
+ * keys in it. Once keys are generated, it can be opened without read-write
+ * subsequently (NSS_Init).
+ */
+ rv = NSS_InitReadWrite(".");
+ if (rv != SECSuccess)
+ {
+ fprintf(stderr, "NSS initialization failed (err %d)\n",
+ PR_GetError());
+ exit(1);
+ }
+
+ /* generate a key with id 1. should succeed on first run on a fresh db,
+ * should fail on successive runs because key with that id already exists */
+ genkey(1);
+
+ /* generate a key with id 2. should succeed on first run on a fresh db,
+ * should fail on successive runs because key with that id already exists */
+ genkey(2);
+
+ /* generate a key with id 1 - this will fail because key with that id
+ * already exists */
+ genkey(1);
+ }
+
+
+ void genkey(int id)
+ {
+ PK11SlotInfo* slot = NULL;
+ PK11SymKey* key = NULL;
+ SECItem keyiditem;
+ int keyid[1];
+ CK_MECHANISM_TYPE cipherMech;
+
+ /* using CKM_AES_CBC_PAD mechanism for example */
+ cipherMech = CKM_AES_CBC_PAD;
+
+ slot = PK11_GetInternalKeySlot();
+ /* slot = PK11_GetBestSlot(cipherMech, NULL); didn't work.
+ * Error code: token is read-only. ??
+ */
+ if (slot == NULL)
+ {
+ fprintf(stderr, "Unable to find security device (err %d)\n",
+ PR_GetError());
+ return;
+ }
+
+ keyid[0] = id;
+ keyiditem.type = siBuffer;
+ keyiditem.data = (void *)keyid;
+ keyiditem.len = sizeof(keyid[0]);
+
+ /* Note: keysize must be 0 for fixed key-length algorithms like DES.
+ * Since we're using AES in this example, we're specifying
+ * one of the valid keysizes (16, 24, 32)
+ */
+ key = PK11_TokenKeyGen(slot, cipherMech, 0, 32 /*keysize*/,
+ &keyiditem, PR_TRUE, 0);
+ if (key == NULL)
+ {
+ fprintf(stderr, "PK11_TokenKeyGen failed (err %d)\n",
+ PR_GetError());
+ PK11_FreeSlot(slot);
+ return;
+ }
+
+ fprintf(stderr, "key length of generated key is %d\n",
+ PK11_GetKeyLength(key));
+ fprintf(stderr, "mechanism of key is %d (asked for %d)\n",
+ PK11_GetMechanism(key), cipherMech);
+
+ PK11_FreeSymKey(key);
+
+
+ key = PK11_FindFixedKey(slot, cipherMech, &keyiditem, 0);
+ if (key == NULL)
+ {
+ fprintf(stderr, "PK11_FindFixedKey failed (err %d)\n",
+ PR_GetError());
+ PK11_FreeSlot(slot);
+ return;
+ }
+
+ fprintf(stderr, "Found key!\n");
+ fprintf(stderr, "key length of generated key is %d\n",
+ PK11_GetKeyLength(key));
+ fprintf(stderr, "mechanism of key is %d (asked for %d)\n",
+ PK11_GetMechanism(key), cipherMech);
+
+ PK11_FreeSymKey(key);
+
+ PK11_FreeSlot(slot);
+ }
+
+ char *passwdcb(PK11SlotInfo *info, PRBool retry, void *arg)
+ {
+ if (!retry)
+ return PL_strdup("test");
+ else
+ return NULL;
+ } \ No newline at end of file
diff --git a/security/nss/doc/rst/legacy/nss_sample_code/nss_sample_code_sample_1_hashing/index.rst b/security/nss/doc/rst/legacy/nss_sample_code/nss_sample_code_sample_1_hashing/index.rst
new file mode 100644
index 0000000000..5ea9c8cadd
--- /dev/null
+++ b/security/nss/doc/rst/legacy/nss_sample_code/nss_sample_code_sample_1_hashing/index.rst
@@ -0,0 +1,253 @@
+.. _mozilla_projects_nss_nss_sample_code_nss_sample_code_sample_1_hashing:
+
+NSS Sample Code Sample_1_Hashing
+================================
+
+.. _nss_sample_code_1_hashing_a_file.:
+
+`NSS Sample Code 1: Hashing a file. <#nss_sample_code_1_hashing_a_file.>`__
+---------------------------------------------------------------------------
+
+.. container::
+
+ This is an example program that demonstrates how to compute the hash of a file and save it to
+ another file. This program illustrates the use of NSS message APIs.
+
+.. _sample_code_1:
+
+`Sample Code 1 <#sample_code_1>`__
+~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
+
+.. container::
+
+ .. code:: c
+
+ /* NSPR Headers */
+ #include <prprf.h>
+ #include <prtypes.h>
+ #include <plgetopt.h>
+ #include <prio.h>
+
+ /* NSS headers */
+ #include <secoid.h>
+ #include <secmodt.h>
+ #include <sechash.h>
+
+ typedef struct {
+ const char *hashName;
+ SECOidTag oid;
+ } NameTagPair;
+
+ /* The hash algorithms supported */
+ static const NameTagPair HASH_NAMES[] = {
+ { "MD2", SEC_OID_MD2 },
+ { "MD5", SEC_OID_MD5 },
+ { "SHA1", SEC_OID_SHA1 },
+ { "SHA256", SEC_OID_SHA256 },
+ { "SHA384", SEC_OID_SHA384 },
+ { "SHA512", SEC_OID_SHA512 }
+ };
+
+ /*
+ * Maps a hash name to a SECOidTag.
+ * Returns NULL if the name is not a supported algorithm
+ */
+ static SECOidTag HashNameToOIDTag(const char *hashName)
+ {
+ int i, nhashes = sizeof(HASH_NAMES);
+ SECOidTag hashtag = SEC_OID_UNKNOWN;
+
+ for (i = 0; i < nhashes; i++) {
+ if (PORT_Strcasecmp(hashName, HASH_NAMES[i].hashName) == 0) {
+ hashtag = HASH_NAMES[i].oid;
+ break;
+ }
+ }
+ return hashtag;
+ }
+
+ /*
+ * Newline
+ */
+ static void Newline(PRFileDesc* out) { PR_fprintf(out, "\n"); }
+
+ /*
+ * PrintAsHex
+ */
+ void PrintAsHex(PRFileDesc* out, unsigned char *data, unsigned int len)
+ {
+ unsigned i;
+ int column;
+ unsigned int limit = 15;
+ unsigned int level = 1;
+
+ column = level;
+ if (!len) {
+ PR_fprintf(out, "(empty)\n");
+ return;
+ }
+
+ for (i = 0; i < len; i++) {
+ if (i != len - 1) {
+ PR_fprintf(out, "%02x:", data[i]);
+ column += 3;
+ } else {
+ PR_fprintf(out, "%02x", data[i]);
+ column += 2;
+ break;
+ }
+ if (column > 76 || (i % 16 == limit)) {
+ Newline(out);
+ column = level;
+ limit = i % 16;
+ }
+ }
+ if (column != level) {
+ Newline(out);
+ }
+ }
+
+ /*
+ * Prints a usage message and exits
+ */
+ static void Usage(const char *progName)
+ {
+ int htype;
+ int HASH_AlgTOTAL = sizeof(HASH_NAMES) / sizeof(HASH_NAMES[0]);
+
+ fprintf(stderr, "Usage: %s -t type [ < input ] [ > output ]\n", progName);
+ fprintf(stderr, "%-20s Specify the digest method (must be one of\n",
+ "-t type");
+ fprintf(stderr, "%-20s ", "");
+ for (htype = 0; htype < HASH_AlgTOTAL; htype++) {
+ fprintf(stderr, HASH_NAMES[htype].hashName);
+ if (htype == (HASH_AlgTOTAL - 2))
+ fprintf(stderr, " or ");
+ else if (htype != (HASH_AlgTOTAL - 1))
+ fprintf(stderr, ", ");
+ }
+ fprintf(stderr, " (case ignored))\n");
+ fprintf(stderr, "%-20s Define an input file to use (default is stdin)\n",
+ "< input");
+ fprintf(stderr, "%-20s Define an output file to use (default is stdout)\n",
+ "> output");
+ exit(-1);
+ }
+
+ /*
+ * Check for the missing arguments
+ */
+ static void PrintMsgAndExit(const char *progName, char opt)
+ {
+ fprintf(stderr, "%s: option -%c requires an argument\n", progName, opt);
+ Usage(progName);
+ }
+
+ #define REQUIRE_ARG(opt,value) if (!(value)) PrintMsgAndExit(progName, opt)
+
+ /*
+ * Digests a file according to the specified algorithm.
+ * It writes out the digest as a hexadecimal string.
+ */
+ static int DigestFile(PRFileDesc *outFile, PRFileDesc *inFile, SECOidTag hashOIDTag)
+ {
+ unsigned int nb;
+ unsigned char ibuf[4096];
+ unsigned char digest[64];
+ unsigned int len;
+ unsigned int digestLen;
+ HASH_HashType hashType;
+ HASHContext *hashContext = NULL;
+
+ hashType = HASH_GetHashTypeByOidTag(hashOIDTag);
+ hashContext = HASH_Create(hashType);
+ if (hashContext == NULL) {
+ return SECFailure;
+ }
+
+ do {
+
+ HASH_Begin(hashContext);
+
+ /* Incrementally hash the file contents */
+ while ((nb = PR_Read(inFile, ibuf, sizeof(ibuf))) > 0) {
+ HASH_Update(hashContext, ibuf, nb);
+ }
+
+ HASH_End(hashContext, digest, &len, 64);
+
+ /* Normally we would write it out in binary with
+ * nb = PR_Write(outFile, digest, len);
+ * but for illustration let's print it in hex.
+ */
+ PrintAsHex(outFile, digest, len);
+
+ } while (0);
+
+ /* cleanup */
+ if (hashContext != NULL)
+ HASH_Destroy(hashContext);
+
+ return SECSuccess;
+ }
+
+ /*
+ * This sample computes the hash of a file and saves it
+ * to another file. It illustrates the use of NSS message
+ * APIs.
+ */
+ int main(int argc, char **argv)
+ {
+ SECOidTag hashOIDTag;
+ PLOptState *optstate;
+ PLOptStatus status;
+ SECStatus rv;
+ char *hashName = NULL;
+ char *progName = strrchr(argv[0], '/');
+
+ progName = progName ? progName + 1 : argv[0];
+
+ rv = NSS_NoDB_Init("/tmp");
+ if (rv != SECSuccess) {
+ fprintf(stderr, "%s: NSS_Init failed in directory %s\n",
+ progName, "/tmp");
+ return -1;
+ }
+
+ /* Parse command line arguments */
+ optstate = PL_CreateOptState(argc, argv, "t:");
+ while ((status = PL_GetNextOpt(optstate)) == PL_OPT_OK) {
+ switch (optstate->option) {
+ case 't':
+ REQUIRE_ARG(optstate->option, optstate->value);
+ hashName = strdup(optstate->value);
+ break;
+ }
+ }
+
+ if (!hashName)
+ Usage(progName);
+
+ /* convert and validate */
+ hashOIDTag = HashNameToOIDTag(hashName);
+ if (hashOIDTag == SEC_OID_UNKNOWN) {
+ fprintf(stderr, "%s: invalid digest type - %s\n", progName, hashName);
+ Usage(progName);
+ }
+
+ /* Digest it and print the result */
+ rv = DigestFile(PR_STDOUT, PR_STDIN, hashOIDTag);
+ if (rv != SECSuccess) {
+ fprintf(stderr, "%s: problem digesting data (%d)\n",
+ progName, PORT_GetError());
+ }
+
+ rv = NSS_Shutdown();
+ if (rv != SECSuccess) {
+ exit(-1);
+ }
+
+ return 0;
+ }
+
+ </sechash.h></secmodt.h></secoid.h></prio.h></plgetopt.h></prtypes.h></prprf.h> \ No newline at end of file
diff --git a/security/nss/doc/rst/legacy/nss_sample_code/nss_sample_code_sample_2_initialization_of_nss/index.rst b/security/nss/doc/rst/legacy/nss_sample_code/nss_sample_code_sample_2_initialization_of_nss/index.rst
new file mode 100644
index 0000000000..a8ad843b49
--- /dev/null
+++ b/security/nss/doc/rst/legacy/nss_sample_code/nss_sample_code_sample_2_initialization_of_nss/index.rst
@@ -0,0 +1,257 @@
+.. _mozilla_projects_nss_nss_sample_code_nss_sample_code_sample_2_initialization_of_nss:
+
+NSS Sample Code Sample_2_Initialization of NSS
+==============================================
+
+.. _nss_sample_code_2_initializing_nss:
+
+`NSS Sample Code 2: Initializing NSS <#nss_sample_code_2_initializing_nss>`__
+-----------------------------------------------------------------------------
+
+.. container::
+
+ This example program demonstrates how to initialize the NSS Database. This program illustrates
+ password handling.
+
+.. _sample_code_1:
+
+`Sample Code 1 <#sample_code_1>`__
+~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
+
+.. container::
+
+ .. code:: c
+
+ /* NSPR Headers */
+ #include <prthread.h>
+ #include <plgetopt.h>
+ #include <prprf.h>
+
+ /* NSS headers */
+ #include <nss.h>
+ #include <pk11func.h>
+
+ #include "util.h"
+
+ /* Print a usage message and exit */
+ static void Usage(const char *progName)
+ {
+ fprintf(stderr, "\nUsage: %s -d <dbdirpath> [-p <plainpasswc>]"
+ " [-f <passwdffile>]\n\n",
+ progName);
+ fprintf(stderr, "%-15s Specify a DB directory path\n\n",
+ "-d <dbdirpath>");
+ fprintf(stderr, "%-15s Specify a plaintext password\n\n",
+ "-p <plainpasswc>");
+ fprintf(stderr, "%-15s Specify a password file\n\n",
+ "-f <plainpasswc>");
+ exit(-1);
+ }
+
+ /* Initialize the slot password */
+ char *InitSlotPassword(PK11SlotInfo *slot, PRBool retry, void *arg)
+ {
+ FILE *input;
+ FILE *output;
+ char *p0 = NULL;
+ char *p1 = NULL;
+ secuPWData *pwdata = (secuPWData *) arg;
+
+ if (pwdata->source == PW_FROMFILE) {
+ return FilePasswd(slot, retry, pwdata->data);
+ }
+ if (pwdata->source == PW_PLAINTEXT) {
+ return PL_strdup(pwdata->data);
+ }
+
+ /* open terminal */
+ input = fopen("/dev/tty", "r");
+ if (input == NULL) {
+ PR_fprintf(PR_STDERR, "Error opening input terminal for read\n");
+ return NULL;
+ }
+
+ /* we have no password, so initialize database with one */
+ PR_fprintf(PR_STDERR,
+ "Enter a password which will be used to encrypt your keys.\n"
+ "The password should be at least 8 characters long,\n"
+ "and should contain at least one non-alphabetic character.\n\n");
+
+ output = fopen("/dev/tty", "w");
+ if (output == NULL) {
+ PR_fprintf(PR_STDERR, "Error opening output terminal for write\n");
+ return NULL;
+ }
+
+ for (;;) {
+ if (p0)
+ PORT_Free(p0);
+ p0 = GetPassword(input, output, "Enter new password: ",
+ CheckPassword);
+ if (p1)
+ PORT_Free(p1);
+ p1 = GetPassword(input, output, "Re-enter password: ",
+ CheckPassword);
+ if (p0 && p1 && !PORT_Strcmp(p0, p1)) {
+ break;
+ }
+ PR_fprintf(PR_STDERR, "Passwords do not match. Try again.\n");
+ }
+
+ /* clear out the duplicate password string */
+ if (p1) {
+ PORT_Memset(p1, 0, PORT_Strlen(p1));
+ PORT_Free(p1);
+ }
+ fclose(input);
+ fclose(output);
+
+ return p0;
+ }
+
+ /* Change the password */
+ SECStatus ChangePW(PK11SlotInfo *slot, char *oldPass, char *newPass,
+ char *oldPwFile, char *newPwFile)
+ {
+ SECStatus rv;
+ secuPWData pwdata;
+ secuPWData newpwdata;
+ char *oldpw = NULL;
+ char *newpw = NULL;
+
+ if (oldPass) {
+ pwdata.source = PW_PLAINTEXT;
+ pwdata.data = oldPass;
+ } else if (oldPwFile) {
+ pwdata.source = PW_FROMFILE;
+ pwdata.data = oldPwFile;
+ } else {
+ pwdata.source = PW_NONE;
+ pwdata.data = NULL;
+ }
+
+ if (newPass) {
+ newpwdata.source = PW_PLAINTEXT;
+ newpwdata.data = newPass;
+ } else if (newPwFile) {
+ newpwdata.source = PW_FROMFILE;
+ newpwdata.data = NULL;
+ } else {
+ newpwdata.source = PW_NONE;
+ newpwdata.data = NULL;
+ }
+
+ if (PK11_NeedUserInit(slot)) {
+ newpw = InitSlotPassword(slot, PR_FALSE, &pwdata);
+ rv = PK11_InitPin(slot, (char*)NULL, newpw);
+ }
+ else {
+ for (;;) {
+ oldpw = GetModulePassword(slot, PR_FALSE, &pwdata);
+
+ if (PK11_CheckUserPassword(slot, oldpw) != SECSuccess) {
+ if (pwdata.source == PW_NONE) {
+ PR_fprintf(PR_STDERR, "Invalid password. Try again.\n");
+ } else {
+ PR_fprintf(PR_STDERR, "Invalid password.\n");
+ PORT_Memset(oldpw, 0, PL_strlen(oldpw));
+ PORT_Free(oldpw);
+ return SECFailure;
+ }
+ } else {
+ break;
+ }
+ PORT_Free(oldpw);
+ }
+ newpw = InitSlotPassword(slot, PR_FALSE, &newpwdata);
+
+ if (PK11_ChangePW(slot, oldpw, newpw) != SECSuccess) {
+ PR_fprintf(PR_STDERR, "Failed to change password.\n");
+ return SECFailure;
+ }
+ PORT_Memset(oldpw, 0, PL_strlen(oldpw));
+ PORT_Free(oldpw);
+ PR_fprintf(PR_STDOUT, "Password changed successfully.\n");
+ }
+ PORT_Memset(newpw, 0, PL_strlen(newpw));
+ PORT_Free(newpw);
+ return SECSuccess;
+ }
+
+ /*
+ * This example illustrates initialization of the NSS database.
+ * It creates an nss configuration directory with empty databases
+ * and initializes the databases. It also illustrates techniques for
+ * password handling.
+ */
+ int main(int argc, char **argv)
+ {
+ PLOptState *optstate;
+ PLOptStatus status;
+ SECStatus rv;
+ SECStatus rvShutdown;
+ char *slotname = "internal";
+ PK11SlotInfo *slot = NULL;
+ char *dbdir = NULL;
+ char *plainPass = NULL;
+ char *pwFile = NULL;
+
+ char * progName = strrchr(argv[0], '/');
+ progName = progName ? progName + 1 : argv[0];
+
+ /* Parse command line arguments */
+ optstate = PL_CreateOptState(argc, argv, "d:p:q:f:g:");
+ while ((status = PL_GetNextOpt(optstate)) == PL_OPT_OK) {
+ switch (optstate->option) {
+ case 'd':
+ dbdir = strdup(optstate->value);
+ break;
+ case 'p':
+ plainPass = strdup(optstate->value);
+ break;
+ case 'f':
+ pwFile = strdup(optstate->value);
+ break;
+ default:
+ Usage(progName);
+ break;
+ }
+ }
+ PL_DestroyOptState(optstate);
+
+ if (!dbdir)
+ Usage(progName);
+
+ PR_Init(PR_USER_THREAD, PR_PRIORITY_NORMAL, 0);
+
+ /* Create the database */
+ rv = NSS_InitReadWrite(dbdir);
+ if (rv != SECSuccess) {
+ PR_fprintf(PR_STDERR, "NSS_Initialize Failed");
+ PR_Cleanup();
+ exit(rv);
+ }
+
+ if (PL_strcmp(slotname, "internal") == 0)
+ slot = PK11_GetInternalKeySlot();
+
+ /* If creating new database, initialize the password. */
+ rv = ChangePW(slot, plainPass, 0, pwFile, 0);
+ if (rv != SECSuccess) {
+ PR_fprintf(PR_STDERR, "Failed to change password\n");
+ }
+
+ if (slot) {
+ PK11_FreeSlot(slot);
+ }
+ rvShutdown = NSS_Shutdown();
+ if (rvShutdown != SECSuccess) {
+ PR_fprintf(PR_STDERR, "Failed : NSS_Shutdown()\n");
+ rv = SECFailure;
+ }
+
+ PR_Cleanup();
+
+ return rv;
+ }
+ </plainpasswc></plainpasswc></dbdirpath></passwdffile></plainpasswc></dbdirpath></pk11func.h></nss.h></prprf.h></plgetopt.h></prthread.h> \ No newline at end of file
diff --git a/security/nss/doc/rst/legacy/nss_sample_code/nss_sample_code_sample_3_basic_encryption_and_maci/index.rst b/security/nss/doc/rst/legacy/nss_sample_code/nss_sample_code_sample_3_basic_encryption_and_maci/index.rst
new file mode 100644
index 0000000000..059c6861b8
--- /dev/null
+++ b/security/nss/doc/rst/legacy/nss_sample_code/nss_sample_code_sample_3_basic_encryption_and_maci/index.rst
@@ -0,0 +1,1221 @@
+.. _mozilla_projects_nss_nss_sample_code_nss_sample_code_sample_3_basic_encryption_and_maci:
+
+NSS Sample Code Sample_3_Basic Encryption and MACing
+====================================================
+
+.. _nss_sample_code_3_basic_encryption_and_macing:
+
+`NSS Sample Code 3: Basic Encryption and MACing <#nss_sample_code_3_basic_encryption_and_macing>`__
+---------------------------------------------------------------------------------------------------
+
+.. container::
+
+ This example program demonstrates how to encrypt and MAC a file.
+
+.. _sample_code_3:
+
+`Sample Code 3 <#sample_code_3>`__
+~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
+
+.. container::
+
+ .. code:: c
+
+ /* 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"
+
+ #define BUFFERSIZE 80
+ #define DIGESTSIZE 16
+ #define PTEXT_MAC_BUFFER_SIZE 96
+ #define CIPHERSIZE 96
+ #define BLOCKSIZE 32
+
+ #define CIPHER_HEADER "-----BEGIN CIPHER-----"
+ #define CIPHER_TRAILER "-----END CIPHER-----"
+ #define ENCKEY_HEADER "-----BEGIN AESKEY CKAID-----"
+ #define ENCKEY_TRAILER "-----END AESKEY CKAID-----"
+ #define MACKEY_HEADER "-----BEGIN MACKEY CKAID-----"
+ #define MACKEY_TRAILER "-----END MACKEY CKAID-----"
+ #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-----"
+
+ typedef enum {
+ ENCRYPT,
+ DECRYPT,
+ UNKNOWN
+ } CommandType;
+
+ typedef enum {
+ SYMKEY = 0,
+ MACKEY = 1,
+ IV = 2,
+ MAC = 3,
+ PAD = 4
+ } HeaderType;
+
+
+ /* Print a usage message and exit */
+ static void Usage(const char *progName)
+ {
+ fprintf(stderr, "\nUsage: %s -c <a|b> -d <dbdirpath> [-z <noisefilename>] "
+ "[-p <dbpwd> | -f <dbpwdfile>] -i <ipfilename> -o <opfilename>\n\n",
+ progName);
+ fprintf(stderr, "%-20s Specify 'a' for encrypt operation\n\n",
+ "-c <a|b>");
+ fprintf(stderr, "%-20s Specify 'b' for decrypt operation\n\n",
+ " ");
+ fprintf(stderr, "%-20s Specify db directory path\n\n",
+ "-d <dbdirpath>");
+ fprintf(stderr, "%-20s Specify db password [optional]\n\n",
+ "-p <dbpwd>");
+ fprintf(stderr, "%-20s Specify db password file [optional]\n\n",
+ "-f <dbpwdfile>");
+ fprintf(stderr, "%-20s Specify noise file name [optional]\n\n",
+ "-z <noisefilename>");
+ fprintf(stderr, "%-21s Specify an input file name\n\n",
+ "-i <ipfilename>");
+ fprintf(stderr, "%-21s Specify an output file name\n\n",
+ "-o <opfilename>");
+ fprintf(stderr, "%-7s For encrypt, it takes <ipfilename> as an input file and produces\n",
+ "Note :");
+ fprintf(stderr, "%-7s <ipfilename>.enc and <ipfilename>.header as intermediate output files.\n\n",
+ "");
+ fprintf(stderr, "%-7s For decrypt, it takes <ipfilename>.enc and <ipfilename>.header\n",
+ "");
+ fprintf(stderr, "%-7s as input files and produces <opfilename> as a final output file.\n\n",
+ "");
+ exit(-1);
+ }
+
+ /* 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>
+
+ /*
+ * Gather a CKA_ID
+ */
+ SECStatus
+ GatherCKA_ID(PK11SymKey* key, SECItem* buf)
+ {
+ SECStatus rv = PK11_ReadRawAttribute(PK11_TypeSymKey, key, CKA_ID, buf);
+ if (rv != SECSuccess) {
+ PR_fprintf(PR_STDERR, "PK11_ReadRawAttribute returned (%d)\n", rv);
+ PR_fprintf(PR_STDERR, "Could not read SymKey CKA_ID attribute\n");
+ return rv;
+ }
+ return rv;
+ }
+
+ /*
+ * Generate a Symmetric Key
+ */
+ PK11SymKey *
+ GenerateSYMKey(PK11SlotInfo *slot, CK_MECHANISM_TYPE mechanism,
+ int keySize, SECItem *keyID, secuPWData *pwdata)
+ {
+ SECStatus rv;
+ PK11SymKey *key;
+
+ 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));
+ return NULL;
+ }
+ }
+
+ /* Generate the symmetric key */
+ key = PK11_TokenKeyGen(slot, mechanism,
+ NULL, keySize, keyID, PR_TRUE, pwdata);
+
+ if (!key) {
+ PR_fprintf(PR_STDERR, "Symmetric Key Generation Failed \n");
+ }
+
+ return key;
+ }
+
+ /*
+ * MacInit
+ */
+ SECStatus
+ MacInit(PK11Context *ctx)
+ {
+ SECStatus rv = PK11_DigestBegin(ctx);
+ if (rv != SECSuccess) {
+ PR_fprintf(PR_STDERR, "Compute MAC Failed : PK11_DigestBegin()\n");
+ }
+ return rv;
+ }
+
+ /*
+ * MacUpdate
+ */
+ SECStatus
+ MacUpdate(PK11Context *ctx,
+ unsigned char *msg, unsigned int msgLen)
+ {
+ SECStatus rv = PK11_DigestOp(ctx, msg, msgLen);
+ if (rv != SECSuccess) {
+ PR_fprintf(PR_STDERR, "Compute MAC Failed : DigestOp()\n");
+ }
+ return rv;
+ }
+
+ /*
+ * Finalize MACing
+ */
+ SECStatus
+ MacFinal(PK11Context *ctx,
+ unsigned char *mac, unsigned int *macLen, unsigned int maxLen)
+ {
+ SECStatus rv = PK11_DigestFinal(ctx, mac, macLen, maxLen);
+ if (rv != SECSuccess) {
+ PR_fprintf(PR_STDERR, "Compute MAC Failed : PK11_DigestFinal()\n");
+ }
+ return SECSuccess;
+ }
+
+ /*
+ * Compute Mac
+ */
+ SECStatus
+ ComputeMac(PK11Context *ctxmac,
+ unsigned char *ptext, unsigned int ptextLen,
+ unsigned char *mac, unsigned int *macLen,
+ unsigned int maxLen)
+ {
+ SECStatus rv = MacInit(ctxmac);
+ if (rv != SECSuccess) return rv;
+ rv = MacUpdate(ctxmac, ptext, ptextLen);
+ if (rv != SECSuccess) return rv;
+ rv = MacFinal(ctxmac, mac, macLen, maxLen);
+ return rv;
+ }
+
+ /*
+ * Write To Header File
+ */
+ SECStatus
+ WriteToHeaderFile(const char *buf, unsigned int len, HeaderType type,
+ PRFileDesc *outFile)
+ {
+ SECStatus rv;
+ char header[40];
+ char trailer[40];
+ char *outString = NULL;
+
+ switch (type) {
+ case SYMKEY:
+ strcpy(header, ENCKEY_HEADER);
+ strcpy(trailer, ENCKEY_TRAILER);
+ break;
+ case MACKEY:
+ strcpy(header, MACKEY_HEADER);
+ strcpy(trailer, MACKEY_TRAILER);
+ break;
+ case IV:
+ strcpy(header, IV_HEADER);
+ strcpy(trailer, IV_TRAILER);
+ break;
+ case MAC:
+ strcpy(header, MAC_HEADER);
+ strcpy(trailer, MAC_TRAILER);
+ break;
+ case PAD:
+ strcpy(header, PAD_HEADER);
+ strcpy(trailer, PAD_TRAILER);
+ break;
+ }
+
+ PR_fprintf(outFile, "%s\n", header);
+ PrintAsHex(outFile, buf, len);
+ PR_fprintf(outFile, "%s\n\n", trailer);
+ return SECSuccess;
+ }
+
+ /*
+ * Initialize for encryption or decryption - common code
+ */
+ PK11Context *
+ CryptInit(PK11SymKey *key,
+ unsigned char *iv, unsigned int ivLen,
+ CK_MECHANISM_TYPE type, CK_ATTRIBUTE_TYPE operation)
+ {
+ SECItem ivItem = { siBuffer, iv, ivLen };
+ PK11Context *ctx = NULL;
+
+ SECItem *secParam = PK11_ParamFromIV(CKM_AES_CBC, &ivItem);
+ if (secParam == NULL) {
+ PR_fprintf(PR_STDERR, "Crypt Failed : secParam NULL\n");
+ return NULL;
+ }
+ ctx = PK11_CreateContextBySymKey(CKM_AES_CBC, operation, key, secParam);
+ if (ctx == NULL) {
+ PR_fprintf(PR_STDERR, "Crypt Failed : can't create a context\n");
+ goto cleanup;
+
+ }
+ cleanup:
+ if (secParam) {
+ SECITEM_FreeItem(secParam, PR_TRUE);
+ }
+ return ctx;
+ }
+
+ /*
+ * Common encryption and decryption code
+ */
+ SECStatus
+ Crypt(PK11Context *ctx,
+ unsigned char *out, unsigned int *outLen, unsigned int maxOut,
+ unsigned char *in, unsigned int inLen)
+ {
+ SECStatus rv;
+
+ rv = PK11_CipherOp(ctx, out, outLen, maxOut, in, inLen);
+ if (rv != SECSuccess) {
+ PR_fprintf(PR_STDERR, "Crypt Failed : PK11_CipherOp returned %d\n", rv);
+ goto cleanup;
+ }
+
+ cleanup:
+ if (rv != SECSuccess) {
+ return rv;
+ }
+ return SECSuccess;
+ }
+
+ /*
+ * Decrypt
+ */
+ SECStatus
+ Decrypt(PK11Context *ctx,
+ unsigned char *out, unsigned int *outLen, unsigned int maxout,
+ unsigned char *in, unsigned int inLen)
+ {
+ return Crypt(ctx, out, outLen, maxout, in, inLen);
+ }
+
+ /*
+ * Encrypt
+ */
+ SECStatus
+ Encrypt(PK11Context* ctx,
+ unsigned char *out, unsigned int *outLen, unsigned int maxout,
+ unsigned char *in, unsigned int inLen)
+ {
+ return Crypt(ctx, out, outLen, maxout, in, inLen);
+ }
+
+ /*
+ * EncryptInit
+ */
+ PK11Context *
+ EncryptInit(PK11SymKey *ek, unsigned char *iv, unsigned int ivLen,
+ CK_MECHANISM_TYPE type)
+ {
+ return CryptInit(ek, iv, ivLen, type, CKA_ENCRYPT);
+ }
+
+ /*
+ * DecryptInit
+ */
+ PK11Context *
+ DecryptInit(PK11SymKey *dk, unsigned char *iv, unsigned int ivLen,
+ CK_MECHANISM_TYPE type)
+ {
+ return CryptInit(dk, iv, ivLen, type, CKA_DECRYPT);
+ }
+
+ /*
+ * Read cryptographic parameters from the header file
+ */
+ SECStatus
+ ReadFromHeaderFile(const char *fileName, HeaderType type,
+ SECItem *item, PRBool isHexData)
+ {
+ SECStatus rv;
+ PRFileDesc* file;
+ SECItem filedata;
+ SECItem outbuf;
+ unsigned char *nonbody;
+ unsigned char *body;
+ char header[40];
+ char trailer[40];
+
+ outbuf.type = siBuffer;
+ file = PR_Open(fileName, PR_RDONLY, 0);
+ if (!file) {
+ PR_fprintf(PR_STDERR, "Failed to open %s\n", fileName);
+ return SECFailure;
+ }
+ switch (type) {
+ case SYMKEY:
+ strcpy(header, ENCKEY_HEADER);
+ strcpy(trailer, ENCKEY_TRAILER);
+ break;
+ case MACKEY:
+ strcpy(header, MACKEY_HEADER);
+ strcpy(trailer, MACKEY_TRAILER);
+ break;
+ case IV:
+ strcpy(header, IV_HEADER);
+ strcpy(trailer, IV_TRAILER);
+ break;
+ case MAC:
+ strcpy(header, MAC_HEADER);
+ strcpy(trailer, MAC_TRAILER);
+ break;
+ case PAD:
+ strcpy(header, PAD_HEADER);
+ strcpy(trailer, PAD_TRAILER);
+ break;
+ }
+
+ 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);
+ return SECFailure;
+ }
+ } else {
+ body = nonbody;
+ }
+
+ cleanup:
+ PR_Close(file);
+ HexToBuf(body, item, isHexData);
+ return SECSuccess;
+ }
+
+ /*
+ * EncryptAndMac
+ */
+ SECStatus
+ EncryptAndMac(PRFileDesc *inFile,
+ PRFileDesc *headerFile,
+ PRFileDesc *encFile,
+ PK11SymKey *ek,
+ PK11SymKey *mk,
+ unsigned char *iv, unsigned int ivLen,
+ PRBool ascii)
+ {
+ SECStatus rv;
+ unsigned char ptext[BLOCKSIZE];
+ unsigned int ptextLen;
+ unsigned char mac[DIGESTSIZE];
+ unsigned int macLen;
+ unsigned int nwritten;
+ unsigned char encbuf[BLOCKSIZE];
+ unsigned int encbufLen;
+ SECItem noParams = { siBuffer, NULL, 0 };
+ PK11Context *ctxmac = NULL;
+ PK11Context *ctxenc = NULL;
+ unsigned int pad[1];
+ SECItem padItem;
+ unsigned int paddingLength;
+
+ static unsigned int firstTime = 1;
+ int j;
+
+ ctxmac = PK11_CreateContextBySymKey(CKM_MD5_HMAC, CKA_SIGN, mk, &noParams);
+ if (ctxmac == NULL) {
+ PR_fprintf(PR_STDERR, "Can't create MAC context\n");
+ rv = SECFailure;
+ goto cleanup;
+ }
+ rv = MacInit(ctxmac);
+ if (rv != SECSuccess) {
+ goto cleanup;
+ }
+
+ ctxenc = EncryptInit(ek, iv, ivLen, CKM_AES_CBC);
+
+ /* read a buffer of plaintext from input file */
+ while ((ptextLen = PR_Read(inFile, ptext, sizeof(ptext))) > 0) {
+
+ /* Encrypt using it using CBC, using previously created IV */
+ if (ptextLen != BLOCKSIZE) {
+ paddingLength = BLOCKSIZE - ptextLen;
+ for ( j=0; j < paddingLength; j++) {
+ ptext[ptextLen+j] = (unsigned char)paddingLength;
+ }
+ ptextLen = BLOCKSIZE;
+ }
+ rv = Encrypt(ctxenc,
+ encbuf, &encbufLen, sizeof(encbuf),
+ ptext, ptextLen);
+ if (rv != SECSuccess) {
+ PR_fprintf(PR_STDERR, "Encrypt Failure\n");
+ goto cleanup;
+ }
+
+ /* save the last block of ciphertext as the next IV */
+ iv = encbuf;
+ ivLen = encbufLen;
+
+ /* write the cipher text to intermediate file */
+ nwritten = PR_Write(encFile, encbuf, encbufLen);
+ /*PR_Assert(nwritten == encbufLen);*/
+
+ rv = MacUpdate(ctxmac, ptext, ptextLen);
+ }
+
+ rv = MacFinal(ctxmac, mac, &macLen, DIGESTSIZE);
+ if (rv != SECSuccess) {
+ PR_fprintf(PR_STDERR, "MacFinal Failure\n");
+ goto cleanup;
+ }
+ if (macLen == 0) {
+ PR_fprintf(PR_STDERR, "Bad MAC length\n");
+ rv = SECFailure;
+ goto cleanup;
+ }
+ WriteToHeaderFile(mac, macLen, MAC, headerFile);
+ if (rv != SECSuccess) {
+ PR_fprintf(PR_STDERR, "Write MAC Failure\n");
+ goto cleanup;
+ }
+
+ pad[0] = paddingLength;
+ padItem.type = siBuffer;
+ padItem.data = (unsigned char *)pad;
+ padItem.len = sizeof(pad[0]);
+
+ WriteToHeaderFile(padItem.data, padItem.len, PAD, headerFile);
+ if (rv != SECSuccess) {
+ PR_fprintf(PR_STDERR, "Write PAD Failure\n");
+ goto cleanup;
+ }
+
+ rv = SECSuccess;
+
+ cleanup:
+ if (ctxmac != NULL) {
+ PK11_DestroyContext(ctxmac, PR_TRUE);
+ }
+ if (ctxenc != NULL) {
+ PK11_DestroyContext(ctxenc, PR_TRUE);
+ }
+
+ return rv;
+ }
+
+ /*
+ * Find the Key for the given mechanism
+ */
+ PK11SymKey*
+ FindKey(PK11SlotInfo *slot,
+ CK_MECHANISM_TYPE mechanism,
+ SECItem *keyBuf, secuPWData *pwdata)
+ {
+ SECStatus rv;
+ PK11SymKey *key;
+
+ 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));
+ if (slot) {
+ PK11_FreeSlot(slot);
+ }
+ return NULL;
+ }
+ }
+
+ key = PK11_FindFixedKey(slot, mechanism, keyBuf, 0);
+ if (!key) {
+ PR_fprintf(PR_STDERR,
+ "PK11_FindFixedKey failed (err %d)\n",
+ PR_GetError());
+ PK11_FreeSlot(slot);
+ return NULL;
+ }
+ return key;
+ }
+
+ /*
+ * Decrypt and Verify MAC
+ */
+ SECStatus
+ DecryptAndVerifyMac(
+ const char* outFileName,
+ char *encryptedFileName,
+ SECItem *cItem, SECItem *macItem,
+ PK11SymKey* ek, PK11SymKey* mk, SECItem *ivItem, SECItem *padItem)
+ {
+ SECStatus rv;
+ PRFileDesc* inFile;
+ PRFileDesc* outFile;
+
+ unsigned char decbuf[64];
+ unsigned int decbufLen;
+
+ unsigned char ptext[BLOCKSIZE];
+ unsigned int ptextLen = 0;
+ unsigned char ctext[64];
+ unsigned int ctextLen;
+ unsigned char newmac[DIGESTSIZE];
+ unsigned int newmacLen = 0;
+ unsigned int newptextLen = 0;
+ unsigned int count = 0;
+ unsigned int temp = 0;
+ unsigned int blockNumber = 0;
+ SECItem noParams = { siBuffer, NULL, 0 };
+ PK11Context *ctxmac = NULL;
+ PK11Context *ctxenc = NULL;
+
+ unsigned char iv[BLOCKSIZE];
+ unsigned int ivLen = ivItem->len;
+ unsigned int fileLength;
+ unsigned int paddingLength;
+ int j;
+
+ memcpy(iv, ivItem->data, ivItem->len);
+ paddingLength = (unsigned int)padItem->data[0];
+
+ ctxmac = PK11_CreateContextBySymKey(CKM_MD5_HMAC, CKA_SIGN, mk, &noParams);
+ if (ctxmac == NULL) {
+ PR_fprintf(PR_STDERR, "Can't create MAC context\n");
+ rv = SECFailure;
+ goto cleanup;
+ }
+
+ /* Open the input file. */
+ inFile = PR_Open(encryptedFileName, PR_RDONLY , 0);
+ if (!inFile) {
+ PR_fprintf(PR_STDERR,
+ "Unable to open \"%s\" for writing.\n",
+ encryptedFileName);
+ return SECFailure;
+ }
+ /* Open the output file. */
+ 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);
+ return SECFailure;
+ }
+
+ rv = MacInit(ctxmac);
+ if (rv != SECSuccess) goto cleanup;
+
+ ctxenc = DecryptInit(ek, iv, ivLen, CKM_AES_CBC);
+ fileLength = FileSize(encryptedFileName);
+
+ while ((ctextLen = PR_Read(inFile, ctext, sizeof(ctext))) > 0) {
+
+ count += ctextLen;
+
+ /* decrypt cipher text buffer using CBC and IV */
+
+ rv = Decrypt(ctxenc, decbuf, &decbufLen, sizeof(decbuf),
+ ctext, ctextLen);
+
+ if (rv != SECSuccess) {
+ PR_fprintf(PR_STDERR, "Decrypt Failure\n");
+ goto cleanup;
+ }
+
+ if (decbufLen == 0) break;
+
+ rv = MacUpdate(ctxmac, decbuf, decbufLen);
+ if (rv != SECSuccess) { goto cleanup; }
+ if (count == fileLength) {
+ 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;
+ }
+
+ /* save last block of ciphertext */
+ memcpy(iv, decbuf, decbufLen);
+ ivLen = decbufLen;
+ blockNumber++;
+ }
+
+ if (rv != SECSuccess) { goto cleanup; }
+
+ rv = MacFinal(ctxmac, newmac, &newmacLen, sizeof(newmac));
+ if (rv != SECSuccess) { goto cleanup; }
+
+ if (PORT_Memcmp(macItem->data, newmac, newmacLen) == 0) {
+ rv = SECSuccess;
+ } else {
+ PR_fprintf(PR_STDERR, "Check MAC : Failure\n");
+ PR_fprintf(PR_STDERR, "Extracted : ");
+ PrintAsHex(PR_STDERR, macItem->data, macItem->len);
+ PR_fprintf(PR_STDERR, "Computed : ");
+ PrintAsHex(PR_STDERR, newmac, newmacLen);
+ rv = SECFailure;
+ }
+ cleanup:
+ if (ctxmac) {
+ PK11_DestroyContext(ctxmac, PR_TRUE);
+ }
+ if (ctxenc) {
+ PK11_DestroyContext(ctxenc, PR_TRUE);
+ }
+ if (outFile) {
+ PR_Close(outFile);
+ }
+
+ return rv;
+ }
+
+ /*
+ * Gets IV and CKAIDs From Header File
+ */
+ SECStatus
+ GetIVandCKAIDSFromHeader(const char *cipherFileName,
+ SECItem *ivItem, SECItem *encKeyItem, SECItem *macKeyItem)
+ {
+ SECStatus rv;
+
+ /* open intermediate file, read in header, get IV and CKA_IDs of two keys
+ * from it
+ */
+ rv = ReadFromHeaderFile(cipherFileName, IV, ivItem, PR_TRUE);
+ if (rv != SECSuccess) {
+ PR_fprintf(PR_STDERR, "Could not retrieve IV from cipher file\n");
+ goto cleanup;
+ }
+
+ rv = ReadFromHeaderFile(cipherFileName, SYMKEY, encKeyItem, PR_TRUE);
+ if (rv != SECSuccess) {
+ PR_fprintf(PR_STDERR,
+ "Could not retrieve AES CKA_ID from cipher file\n");
+ goto cleanup;
+ }
+ rv = ReadFromHeaderFile(cipherFileName, MACKEY, macKeyItem, PR_TRUE);
+ if (rv != SECSuccess) {
+ PR_fprintf(PR_STDERR,
+ "Could not retrieve MAC CKA_ID from cipher file\n");
+ goto cleanup;
+ }
+ cleanup:
+ return rv;
+ }
+
+ /*
+ * Decrypt a File
+ */
+ SECStatus
+ DecryptFile(PK11SlotInfo *slot,
+ const char *dbdir,
+ const char *outFileName,
+ const char *headerFileName,
+ char *encryptedFileName,
+ secuPWData *pwdata,
+ PRBool ascii)
+ {
+ /*
+ * The DB is open read only and we have authenticated to it
+ * open input file, read in header, get IV and CKA_IDs of two keys from it
+ * find those keys in the DB token
+ * Open output file
+ * loop until EOF(input):
+ * read a buffer of ciphertext from input file
+ * save last block of ciphertext
+ * decrypt ciphertext buffer using CBC and IV
+ * compute and check MAC, then remove MAC from plaintext
+ * replace IV with saved last block of ciphertext
+ * write the plain text to output file
+ * close files
+ * report success
+ */
+
+ SECStatus rv;
+ SECItem ivItem;
+ SECItem encKeyItem;
+ SECItem macKeyItem;
+ SECItem cipherItem;
+ SECItem macItem;
+ SECItem padItem;
+ PK11SymKey *encKey = NULL;
+ PK11SymKey *macKey = NULL;
+
+
+ /* open intermediate file, read in header, get IV and CKA_IDs of two keys
+ * from it
+ */
+ rv = GetIVandCKAIDSFromHeader(headerFileName,
+ &ivItem, &encKeyItem, &macKeyItem);
+ if (rv != SECSuccess) {
+ goto cleanup;
+ }
+
+ /* find those keys in the DB token */
+ encKey = FindKey(slot, CKM_AES_CBC, &encKeyItem, pwdata);
+ if (encKey == NULL) {
+ PR_fprintf(PR_STDERR, "Can't find the encryption key\n");
+ rv = SECFailure;
+ goto cleanup;
+ }
+ /* CKM_MD5_HMAC or CKM_EXTRACT_KEY_FROM_KEY */
+ macKey = FindKey(slot, CKM_MD5_HMAC, &macKeyItem, pwdata);
+ if (macKey == NULL) {
+ rv = SECFailure;
+ goto cleanup;
+ }
+
+ /* Read in the Mac into item from the intermediate file */
+ rv = ReadFromHeaderFile(headerFileName, MAC, &macItem, PR_TRUE);
+ if (rv != SECSuccess) {
+ PR_fprintf(PR_STDERR,
+ "Could not retrieve MAC from cipher file\n");
+ goto cleanup;
+ }
+ if (macItem.data == NULL) {
+ PR_fprintf(PR_STDERR, "MAC has NULL data\n");
+ rv = SECFailure;
+ goto cleanup;
+ }
+ if (macItem.len == 0) {
+ PR_fprintf(PR_STDERR, "MAC has data has 0 length\n");
+ /*rv = SECFailure;
+ goto cleanup;*/
+ }
+
+ 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;
+ }
+
+ if (rv == SECSuccess) {
+ /* Decrypt and Remove Mac */
+ rv = DecryptAndVerifyMac(outFileName, encryptedFileName,
+ &cipherItem, &macItem, encKey, macKey, &ivItem, &padItem);
+ if (rv != SECSuccess) {
+ PR_fprintf(PR_STDERR, "Failed while decrypting and removing MAC\n");
+ }
+ }
+
+ cleanup:
+ if (slot) {
+ PK11_FreeSlot(slot);
+ }
+ if (encKey) {
+ PK11_FreeSymKey(encKey);
+ }
+ if (macKey) {
+ PK11_FreeSymKey(macKey);
+ }
+
+ return rv;
+ }
+
+ /*
+ * Encrypt a File
+ */
+ SECStatus
+ EncryptFile(
+ PK11SlotInfo *slot,
+ const char *dbdir,
+ const char *inFileName,
+ const char *headerFileName,
+ const char *encryptedFileName,
+ const char *noiseFileName,
+ secuPWData *pwdata,
+ PRBool ascii)
+ {
+ /*
+ * The DB is open for read/write and we have authenticated to it.
+ * generate a symmetric AES key as a token object.
+ * generate a second key to use for MACing, also a token object.
+ * get their CKA_IDs
+ * generate a random value to use as IV for AES CBC
+ * open an input file and an output file,
+ * write a header to the output that identifies the two keys by
+ * their CKA_IDs, May include original file name and length.
+ * loop until EOF(input)
+ * read a buffer of plaintext from input file
+ * MAC it, append the MAC to the plaintext
+ * encrypt it using CBC, using previously created IV
+ * store the last block of ciphertext as the new IV
+ * write the cipher text to intermediate file
+ * close files
+ * report success
+ */
+ SECStatus rv;
+ PRFileDesc *inFile;
+ PRFileDesc *headerFile;
+ PRFileDesc *encFile;
+
+ unsigned char *encKeyId = (unsigned char *) "Encrypt Key";
+ unsigned char *macKeyId = (unsigned char *) "MAC Key";
+ SECItem encKeyID = { siAsciiString, encKeyId, PL_strlen(encKeyId) };
+ SECItem macKeyID = { siAsciiString, macKeyId, PL_strlen(macKeyId) };
+
+ SECItem encCKAID;
+ SECItem macCKAID;
+ unsigned char iv[BLOCKSIZE];
+ SECItem ivItem;
+ PK11SymKey *encKey = NULL;
+ PK11SymKey *macKey = NULL;
+ SECItem temp;
+ unsigned char c;
+
+ /* generate a symmetric AES key as a token object. */
+ encKey = GenerateSYMKey(slot, CKM_AES_KEY_GEN, 128/8, &encKeyID, pwdata);
+ if (encKey == NULL) {
+ PR_fprintf(PR_STDERR, "GenerateSYMKey for AES returned NULL.\n");
+ rv = SECFailure;
+ goto cleanup;
+ }
+
+ /* generate a second key to use for MACing, also a token object. */
+ macKey = GenerateSYMKey(slot, CKM_GENERIC_SECRET_KEY_GEN, 160/8,
+ &macKeyID, pwdata);
+ if (macKey == NULL) {
+ PR_fprintf(PR_STDERR, "GenerateSYMKey for MACing returned NULL.\n");
+ rv = SECFailure;
+ goto cleanup;
+ }
+
+ /* get the encrypt key CKA_ID */
+ rv = GatherCKA_ID(encKey, &encCKAID);
+ if (rv != SECSuccess) {
+ PR_fprintf(PR_STDERR, "Error while wrapping encrypt key\n");
+ goto cleanup;
+ }
+
+ /* get the MAC key CKA_ID */
+ rv = GatherCKA_ID(macKey, &macCKAID);
+ if (rv != SECSuccess) {
+ PR_fprintf(PR_STDERR, "Can't get the MAC key CKA_ID.\n");
+ goto cleanup;
+ }
+
+ if (noiseFileName) {
+ rv = SeedFromNoiseFile(noiseFileName);
+ if (rv != SECSuccess) {
+ PORT_SetError(PR_END_OF_FILE_ERROR);
+ return SECFailure;
+ }
+ rv = PK11_GenerateRandom(iv, BLOCKSIZE);
+ if (rv != SECSuccess) {
+ goto cleanup;
+ }
+
+ } else {
+ /* generate a random value to use as IV for AES CBC */
+ GenerateRandom(iv, BLOCKSIZE);
+ }
+
+ headerFile = PR_Open(headerFileName,
+ PR_CREATE_FILE | PR_TRUNCATE | PR_RDWR, 00660);
+ if (!headerFile) {
+ PR_fprintf(PR_STDERR,
+ "Unable to open \"%s\" for writing.\n",
+ headerFileName);
+ return SECFailure;
+ }
+ 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);
+ return SECFailure;
+ }
+ /* write to a header file the IV and the CKA_IDs
+ * identifying the two keys
+ */
+ ivItem.type = siBuffer;
+ ivItem.data = iv;
+ ivItem.len = BLOCKSIZE;
+
+ rv = WriteToHeaderFile(iv, BLOCKSIZE, IV, headerFile);
+ if (rv != SECSuccess) {
+ PR_fprintf(PR_STDERR, "Error writing IV to cipher file - %s\n",
+ headerFileName);
+ goto cleanup;
+ }
+
+ rv = WriteToHeaderFile(encCKAID.data, encCKAID.len, SYMKEY, headerFile);
+ if (rv != SECSuccess) {
+ PR_fprintf(PR_STDERR, "Error writing AES CKA_ID to cipher file - %s\n",
+ encryptedFileName);
+ goto cleanup;
+ }
+ rv = WriteToHeaderFile(macCKAID.data, macCKAID.len, MACKEY, headerFile);
+ if (rv != SECSuccess) {
+ PR_fprintf(PR_STDERR, "Error writing MAC CKA_ID to cipher file - %s\n",
+ headerFileName);
+ goto cleanup;
+ }
+
+ /* 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);
+ return SECFailure;
+ }
+
+ /* Macing and Encryption */
+ if (rv == SECSuccess) {
+ rv = EncryptAndMac(inFile, headerFile, encFile,
+ encKey, macKey, ivItem.data, ivItem.len, ascii);
+ if (rv != SECSuccess) {
+ PR_fprintf(PR_STDERR, "Failed : MACing and Encryption\n");
+ goto cleanup;
+ }
+ }
+
+ cleanup:
+ if (inFile) {
+ PR_Close(inFile);
+ }
+ if (headerFile) {
+ PR_Close(headerFile);
+ }
+ if (encFile) {
+ PR_Close(encFile);
+ }
+ if (slot) {
+ PK11_FreeSlot(slot);
+ }
+ if (encKey) {
+ PK11_FreeSymKey(encKey);
+ }
+ if (macKey) {
+ PK11_FreeSymKey(macKey);
+ }
+
+ return rv;
+ }
+
+ /*
+ * This example illustrates basic encryption/decryption and MACing.
+ * Generates the encryption/mac keys and uses token for storing.
+ * Encrypts the input file and appends MAC before storing in intermediate
+ * header file.
+ * Writes the CKA_IDs of the encryption keys into intermediate header file.
+ * Reads the intermediate header file for CKA_IDs and encrypted
+ * contents and decrypts into output file.
+ */
+ int main(int argc, char **argv)
+ {
+ SECStatus rv;
+ SECStatus rvShutdown;
+ PK11SlotInfo *slot = NULL;
+ PLOptState *optstate;
+ PLOptStatus status;
+ char headerFileName[50];
+ char encryptedFileName[50];
+ PRFileDesc *inFile;
+ PRFileDesc *outFile;
+ PRBool ascii = PR_FALSE;
+ CommandType cmd = UNKNOWN;
+ const char *command = NULL;
+ const char *dbdir = NULL;
+ const char *inFileName = NULL;
+ const char *outFileName = NULL;
+ const char *noiseFileName = NULL;
+ secuPWData pwdata = { PW_NONE, 0 };
+
+ char * progName = strrchr(argv[0], '/');
+ progName = progName ? progName + 1 : argv[0];
+
+ /* Parse command line arguments */
+ optstate = PL_CreateOptState(argc, argv, "c:d:i:o:f:p:z:a");
+ while ((status = PL_GetNextOpt(optstate)) == PL_OPT_OK) {
+ switch (optstate->option) {
+ case 'a':
+ ascii = PR_TRUE;
+ break;
+ case 'c':
+ command = strdup(optstate->value);
+ 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 'o':
+ outFileName = strdup(optstate->value);
+ break;
+ case 'z':
+ noiseFileName = strdup(optstate->value);
+ break;
+ default:
+ Usage(progName);
+ break;
+ }
+ }
+ PL_DestroyOptState(optstate);
+
+ if (!command || !dbdir || !inFileName || !outFileName)
+ Usage(progName);
+ if (PL_strlen(command)==0)
+ Usage(progName);
+
+ cmd = command[0] == 'a' ? ENCRYPT : command[0] == 'b' ? DECRYPT : UNKNOWN;
+
+ /* 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);
+ return SECFailure;
+ }
+ PR_Close(inFile);
+
+ /* For intermediate header file, choose filename as inputfile name
+ with extension ".header" */
+ strcpy(headerFileName, inFileName);
+ strcat(headerFileName, ".header");
+
+ /* For intermediate encrypted file, choose filename as inputfile name
+ with extension ".enc" */
+ strcpy(encryptedFileName, inFileName);
+ strcat(encryptedFileName, ".enc");
+
+ PR_Init(PR_USER_THREAD, PR_PRIORITY_NORMAL, 0);
+
+ switch (cmd) {
+ case ENCRYPT:
+ /* If the intermediate header file already exists, delete it */
+ if (PR_Access(headerFileName, PR_ACCESS_EXISTS) == PR_SUCCESS) {
+ PR_Delete(headerFileName);
+ }
+ /* If the intermediate encrypted already exists, delete it */
+ if (PR_Access(encryptedFileName, PR_ACCESS_EXISTS) == PR_SUCCESS) {
+ PR_Delete(encryptedFileName);
+ }
+
+ /* Open DB for read/write and authenticate to it. */
+ 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;
+ }
+ }
+ rv = EncryptFile(slot, dbdir,
+ inFileName, headerFileName, encryptedFileName,
+ noiseFileName, &pwdata, ascii);
+ if (rv != SECSuccess) {
+ PR_fprintf(PR_STDERR, "EncryptFile : Failed\n");
+ return SECFailure;
+ }
+ break;
+ case DECRYPT:
+ /* Open DB read only, authenticate to it */
+ PK11_SetPasswordFunc(GetModulePassword);
+
+ rv = NSS_Init(dbdir);
+ if (rv != SECSuccess) {
+ PR_fprintf(PR_STDERR, "NSS_Init Failed\n");
+ return SECFailure;
+ }
+
+ 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;
+ }
+ }
+
+ rv = DecryptFile(slot, dbdir,
+ outFileName, headerFileName,
+ encryptedFileName, &pwdata, ascii);
+ if (rv != SECSuccess) {
+ PR_fprintf(PR_STDERR, "DecryptFile : Failed\n");
+ return SECFailure;
+ }
+ break;
+ }
+
+ cleanup:
+ rvShutdown = NSS_Shutdown();
+ if (rvShutdown != SECSuccess) {
+ PR_fprintf(PR_STDERR, "Failed : NSS_Shutdown()\n");
+ rv = SECFailure;
+ }
+
+ PR_Cleanup();
+
+ return rv;
+ }
+ </plstr.h></prtypes.h></prlog.h></prinit.h></prerror.h></plgetopt.h></prthread.h></opfilename></ipfilename></ipfilename></ipfilename></ipfilename></ipfilename></opfilename></ipfilename></noisefilename></dbpwdfile></dbpwd></dbdirpath></a|b></opfilename></ipfilename></dbpwdfile></dbpwd></noisefilename></dbdirpath></a|b></pk11priv.h></keyhi.h></plstr.h></prtypes.h></prlog.h></prinit.h></prerror.h></plgetopt.h></prthread.h> \ No newline at end of file
diff --git a/security/nss/doc/rst/legacy/nss_sample_code/nss_sample_code_utililies_1/index.rst b/security/nss/doc/rst/legacy/nss_sample_code/nss_sample_code_utililies_1/index.rst
new file mode 100644
index 0000000000..261b587f9f
--- /dev/null
+++ b/security/nss/doc/rst/legacy/nss_sample_code/nss_sample_code_utililies_1/index.rst
@@ -0,0 +1,553 @@
+.. _mozilla_projects_nss_nss_sample_code_nss_sample_code_utililies_1:
+
+NSS Sample Code Utilities_1
+===========================
+
+.. _nss_sample_code_common_utilities:
+
+`NSS Sample Code Common: Utilities <#nss_sample_code_common_utilities>`__
+-------------------------------------------------------------------------
+
+.. container::
+
+ This is a library of utilities used by many of the samples. This code shows the following:
+
+ - Extract seed from noise file
+ - Read DER encoding from a file
+ - Extract the password from a text file
+ - Get the module password
+ - Print as ascii or hexadecimal
+
+.. _sample_code:
+
+`Sample Code <#sample_code>`__
+~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
+
+.. container::
+
+ .. code::
+
+ #include <prlog.h>
+ #include <termios.h>
+ #include <base64.h>
+ #include <unistd.h>
+ #include <sys/stat.h>
+ #include <prprf.h>
+ #include "util.h"
+
+
+ /*
+ * These utility functions are adapted from those found in
+ * the sectool library used by the NSS security tools and
+ * other NSS test applications.
+ */
+
+ /*
+ * Newline
+ */
+ static void Newline(PRFileDesc* out) {
+ PR_fprintf(out, "\n");
+ }
+
+ /*
+ * PrintAsAscii
+ */
+ void PrintAsAscii(PRFileDesc* out, const unsigned char *data, unsigned int len)
+ {
+ char *b64Data = NULL;
+
+ b64Data = BTOA_DataToAscii(data, len);
+ PR_fprintf(out, "%s", b64Data);
+ PR_fprintf(out, "\n");
+ if (b64Data) {
+ PORT_Free(b64Data);
+ }
+ }
+
+ /*
+ * PrintAsHex
+ */
+ void PrintAsHex(PRFileDesc* out, const unsigned char *data, unsigned int len)
+ {
+ unsigned i;
+ int column;
+ unsigned int limit = 15;
+ unsigned int level = 1;
+
+ column = level;
+ if (!len) {
+ PR_fprintf(out, "(empty)\n");
+ return;
+ }
+
+ for (i = 0; i < len; i++) {
+ if (i != len - 1) {
+ PR_fprintf(out, "%02x:", data[i]);
+ column += 3;
+ } else {
+ PR_fprintf(out, "%02x", data[i]);
+ column += 2;
+ break;
+ }
+ if (column > 76 || (i % 16 == limit)) {
+ Newline(out);
+ column = level;
+ limit = i % 16;
+ }
+ }
+ if (column != level) {
+ Newline(out);
+ }
+ }
+
+ /*
+ * GetDigit
+ */
+ int GetDigit(char c)
+ {
+ if (c == 0) {
+ return -1;
+ }
+ if (c <= '9' && c >= '0') {
+ return c - '0';
+ }
+ if (c <= 'f' && c >= 'a') {
+ return c - 'a' + 0xa;
+ }
+ if (c <= 'F' && c >= 'A') {
+ return c - 'A' + 0xa;
+ }
+ return -1;
+ }
+
+ /*
+ * HexToBuf
+ */
+ int HexToBuf(unsigned char *inString, SECItem *outbuf, PRBool isHexData)
+ {
+ int len = strlen(inString);
+ int outLen = len+1/2;
+ int trueLen = 0;
+ int digit1, digit2;
+
+ outbuf->data = isHexData
+ ? PORT_Alloc(outLen)
+ : PORT_Alloc(len);
+ if (!outbuf->data) {
+ return -1;
+ }
+ if (isHexData) {
+ while (*inString) {
+ if ((*inString == '\n') || (*inString == ':')) {
+ inString++;
+ continue;
+ }
+ digit1 = GetDigit(*inString++);
+ digit2 = GetDigit(*inString++);
+ if ((digit1 == -1) || (digit2 == -1)) {
+ PORT_Free(outbuf->data);
+ outbuf->data = NULL;
+ return -1;
+ }
+ outbuf->data[trueLen++] = digit1 << 4 | digit2;
+ }
+ } else {
+ while (*inString) {
+ if (*inString == '\n') {
+ inString++;
+ continue;
+ }
+ outbuf->data[trueLen++] = *inString++;
+ }
+ outbuf->data[trueLen] = '\0';
+ trueLen = trueLen-1;
+ }
+ outbuf->len = trueLen;
+ return 0;
+ }
+
+ /*
+ * FileToItem
+ */
+ SECStatus FileToItem(SECItem *dst, PRFileDesc *src)
+ {
+ PRFileInfo info;
+ PRInt32 numBytes;
+ PRStatus prStatus;
+
+ prStatus = PR_GetOpenFileInfo(src, &info);
+
+ if (prStatus != PR_SUCCESS) {
+ return SECFailure;
+ }
+
+ dst->data = 0;
+ if (SECITEM_AllocItem(NULL, dst, info.size)) {
+ numBytes = PR_Read(src, dst->data, info.size);
+ if (numBytes == info.size) {
+ return SECSuccess;
+ }
+ }
+ SECITEM_FreeItem(dst, PR_FALSE);
+ dst->data = NULL;
+ return SECFailure;
+ }
+
+ /*
+ * echoOff
+ */
+ static void echoOff(int fd)
+ {
+ if (isatty(fd)) {
+ struct termios tio;
+ tcgetattr(fd, &tio);
+ tio.c_lflag &= ~ECHO;
+ tcsetattr(fd, TCSAFLUSH, &tio);
+ }
+ }
+
+ /*
+ * echoOn
+ */
+ static void echoOn(int fd)
+ {
+ if (isatty(fd)) {
+ struct termios tio;
+ tcgetattr(fd, &tio);
+ tio.c_lflag |= ECHO;
+ tcsetattr(fd, TCSAFLUSH, &tio);
+ }
+ }
+
+ /*
+ * CheckPassword
+ */
+ PRBool CheckPassword(char *cp)
+ {
+ int len;
+ char *end;
+ len = PORT_Strlen(cp);
+ if (len < 8) {
+ return PR_FALSE;
+ }
+ end = cp + len;
+ while (cp < end) {
+ unsigned char ch = *cp++;
+ if (!((ch >= 'A') && (ch <= 'Z')) &&
+ !((ch >= 'a') && (ch <= 'z'))) {
+ return PR_TRUE;
+ }
+ }
+ return PR_FALSE;
+ }
+
+ /*
+ * GetPassword
+ */
+ char* GetPassword(FILE *input, FILE *output, char *prompt,
+ PRBool (*ok)(char *))
+ {
+ char phrase[200] = {'\0'};
+ int infd = fileno(input);
+ int isTTY = isatty(infd);
+
+ for (;;) {
+ /* Prompt for password */
+ if (isTTY) {
+ fprintf(output, "%s", prompt);
+ fflush (output);
+ echoOff(infd);
+ }
+ fgets(phrase, sizeof(phrase), input);
+ if (isTTY) {
+ fprintf(output, "\n");
+ echoOn(infd);
+ }
+ /* stomp on newline */
+ phrase[PORT_Strlen(phrase)-1] = 0;
+ /* Validate password */
+ if (!(*ok)(phrase)) {
+ if (!isTTY) return 0;
+ fprintf(output, "Password must be at least 8 characters long with one or more\n");
+ fprintf(output, "non-alphabetic characters\n");
+ continue;
+ }
+ return (char*) PORT_Strdup(phrase);
+ }
+ }
+
+ /*
+ * FilePasswd extracts the password from a text file
+ *
+ * Storing passwords is often used with server environments
+ * where prompting the user for a password or requiring it
+ * to be entered in the command line is not a feasible option.
+ *
+ * This function supports password extraction from files with
+ * multiple passwords, one for each token. In the single password
+ * case a line would just have the password whereas in the multi-
+ * password variant they could be of the form
+ *
+ * token_1_name:its_password
+ * token_2_name:its_password
+ *
+ */
+ char *FilePasswd(PK11SlotInfo *slot, PRBool retry, void *arg)
+ {
+ char* phrases, *phrase;
+ PRFileDesc *fd;
+ PRInt32 nb;
+ char *pwFile = arg;
+ int i;
+ const long maxPwdFileSize = 4096;
+ char* tokenName = NULL;
+ int tokenLen = 0;
+
+ if (!pwFile)
+ return 0;
+
+ if (retry) {
+ return 0; /* no good retrying - the file contents will be the same */
+ }
+
+ phrases = PORT_ZAlloc(maxPwdFileSize);
+
+ if (!phrases) {
+ return 0; /* out of memory */
+ }
+
+ fd = PR_Open(pwFile, PR_RDONLY, 0);
+ if (!fd) {
+ fprintf(stderr, "No password file \"%s\" exists.\n", pwFile);
+ PORT_Free(phrases);
+ return NULL;
+ }
+
+ nb = PR_Read(fd, phrases, maxPwdFileSize);
+
+ PR_Close(fd);
+
+ if (nb == 0) {
+ fprintf(stderr,"password file contains no data\n");
+ PORT_Free(phrases);
+ return NULL;
+ }
+
+ if (slot) {
+ tokenName = PK11_GetTokenName(slot);
+ if (tokenName) {
+ tokenLen = PORT_Strlen(tokenName);
+ }
+ }
+ i = 0;
+ do {
+ int startphrase = i;
+ int phraseLen;
+
+ /* handle the Windows EOL case */
+ while (phrases[i] != '\r' && phrases[i] != '\n' && i < nb) i++;
+
+ /* terminate passphrase */
+ phrases[i++] = '\0';
+ /* clean up any EOL before the start of the next passphrase */
+ while ( (i<nb) analyze="" char="" current="" getmodulepassword="" if="" int="" now="" passphrase="" phrase="&amp;phrases[startphrase];" phraselen="" pk11slotinfo="" pwdata="=" pwdata-="" retry="" return="" secupwdata="" the="" void="" while="">source != PW_NONE) {
+ PR_fprintf(PR_STDERR, "Incorrect password/PIN entered.\n");
+ return NULL;
+ }
+
+ switch (pwdata->source) {
+ case PW_NONE:
+ sprintf(prompt, "Enter Password or Pin for \"%s\":",
+ PK11_GetTokenName(slot));
+ return GetPassword(stdin, stdout, prompt, CheckPassword);
+ case PW_FROMFILE:
+ pw = FilePasswd(slot, retry, pwdata->data);
+ pwdata->source = PW_PLAINTEXT;
+ pwdata->data = PL_strdup(pw);
+ return pw;
+ case PW_PLAINTEXT:
+ return PL_strdup(pwdata->data);
+ default:
+ break;
+ }
+ PR_fprintf(PR_STDERR, "Password check failed: No password found.\n");
+ return NULL;
+ }
+
+ /*
+ * GenerateRandom
+ */
+ SECStatus GenerateRandom(unsigned char *rbuf, int rsize)
+ {
+ char meter[] = {
+ "\r| |" };
+ int fd, count;
+ int c;
+ SECStatus rv = SECSuccess;
+ cc_t orig_cc_min;
+ cc_t orig_cc_time;
+ tcflag_t orig_lflag;
+ struct termios tio;
+
+ fprintf(stderr, "To generate random numbers, "
+ "continue typing until the progress meter is full:\n\n");
+ fprintf(stderr, "%s", meter);
+ fprintf(stderr, "\r|");
+
+ /* turn off echo on stdin & return on 1 char instead of NL */
+ fd = fileno(stdin);
+
+ tcgetattr(fd, &tio);
+ orig_lflag = tio.c_lflag;
+ orig_cc_min = tio.c_cc[VMIN];
+ orig_cc_time = tio.c_cc[VTIME];
+ tio.c_lflag &= ~ECHO;
+ tio.c_lflag &= ~ICANON;
+ tio.c_cc[VMIN] = 1;
+ tio.c_cc[VTIME] = 0;
+ tcsetattr(fd, TCSAFLUSH, &tio);
+ /* Get random noise from keyboard strokes */
+ count = 0;
+ while (count < rsize) {
+ c = getc(stdin);
+ if (c == EOF) {
+ rv = SECFailure;
+ break;
+ }
+ *(rbuf + count) = c;
+ if (count == 0 || c != *(rbuf + count -1)) {
+ count++;
+ fprintf(stderr, "*");
+ }
+ }
+ rbuf[count] = '\0';
+
+ fprintf(stderr, "\n\nFinished. Press enter to continue: ");
+ while ((c = getc(stdin)) != '\n' && c != EOF)
+ ;
+ if (c == EOF)
+ rv = SECFailure;
+ fprintf(stderr, "\n");
+
+ /* set back termio the way it was */
+ tio.c_lflag = orig_lflag;
+ tio.c_cc[VMIN] = orig_cc_min;
+ tio.c_cc[VTIME] = orig_cc_time;
+ tcsetattr(fd, TCSAFLUSH, &tio);
+ return rv;
+ }
+
+ /*
+ * SeedFromNoiseFile
+ */
+ SECStatus SeedFromNoiseFile(const char *noiseFileName)
+ {
+ char buf[2048];
+ PRFileDesc *fd;
+ PRInt32 count;
+
+ fd = PR_Open(noiseFileName, PR_RDONLY, 0);
+ if (!fd) {
+ fprintf(stderr, "failed to open noise file.");
+ return SECFailure;
+ }
+
+ do {
+ count = PR_Read(fd,buf,sizeof(buf));
+ if (count > 0) {
+ PK11_RandomUpdate(buf,count);
+ }
+ } while (count > 0);
+
+ PR_Close(fd);
+ return SECSuccess;
+ }
+
+ /*
+ * FileSize
+ */
+ long FileSize(const char* filename)
+ {
+ struct stat stbuf;
+ stat(filename, &stbuf);
+ return stbuf.st_size;
+ }
+
+ /*
+ * ReadDERFromFile
+ */
+ SECStatus ReadDERFromFile(SECItem *der, const char *inFileName, PRBool ascii)
+ {
+ SECStatus rv = SECSuccess;
+ PRFileDesc *inFile = NULL;
+
+ inFile = PR_Open(inFileName, PR_RDONLY, 0);
+ if (!inFile) {
+ PR_fprintf(PR_STDERR, "Failed to open file \"%s\" (%ld, %ld).\n",
+ inFileName, PR_GetError(), PR_GetOSError());
+ rv = SECFailure;
+ goto cleanup;
+ }
+
+ if (ascii) {
+ /* First convert ascii to binary */
+ SECItem filedata;
+ char *asc, *body;
+
+ /* Read in ascii data */
+ rv = FileToItem(&filedata, inFile);
+ asc = (char *)filedata.data;
+ if (!asc) {
+ 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(asc, "-----BEGIN")) != NULL) {
+ char *trailer = NULL;
+ asc = body;
+ body = PORT_Strchr(body, '\n');
+ if (!body)
+ body = PORT_Strchr(asc, '\r'); /* maybe this is a MAC file */
+ if (body)
+ trailer = strstr(++body, "-----END");
+ if (trailer != NULL) {
+ *trailer = '\0';
+ } else {
+ PR_fprintf(PR_STDERR, "input has header but no trailer\n");
+ PORT_Free(filedata.data);
+ rv = SECFailure;
+ goto cleanup;
+ }
+ } else {
+ body = asc;
+ }
+
+ /* Convert to binary */
+ rv = ATOB_ConvertAsciiToItem(der, body);
+ if (rv) {
+ PR_fprintf(PR_STDERR, "error converting ascii to binary %s\n",
+ PORT_GetError());
+ PORT_Free(filedata.data);
+ rv = SECFailure;
+ goto cleanup;
+ }
+
+ PORT_Free(filedata.data);
+ } else {
+ /* Read in binary der */
+ rv = FileToItem(der, inFile);
+ if (rv) {
+ PR_fprintf(PR_STDERR, "error converting der \n");
+ rv = SECFailure;
+ }
+ }
+ cleanup:
+ if (inFile) {
+ PR_Close(inFile);
+ }
+ return rv;
+ }
+
+ </nb)> \ No newline at end of file
diff --git a/security/nss/doc/rst/legacy/nss_sample_code/sample1/index.rst b/security/nss/doc/rst/legacy/nss_sample_code/sample1/index.rst
new file mode 100644
index 0000000000..ee1bb2dcf1
--- /dev/null
+++ b/security/nss/doc/rst/legacy/nss_sample_code/sample1/index.rst
@@ -0,0 +1,230 @@
+.. _mozilla_projects_nss_nss_sample_code_sample1:
+
+sample1
+=======
+
+.. container::
+
+ 1. A program to compute the hash of a file and save it to another file.
+
+ .. code:: c
+
+ /* NSPR Headers */
+ #include <prprf.h>
+ #include <prtypes.h>
+ #include <plgetopt.h>
+ #include <prio.h>
+ #include <prprf.h>
+
+ /* NSS headers */
+ #include <secoid.h>
+ #include <secmodt.h>
+ #include <sechash.h>
+
+ typedef struct {
+ const char *hashName;
+ SECOidTag oid;
+ } NameTagPair;
+
+ /* The hash algorithms supported */
+ static const NameTagPair HASH_NAMES[] = {
+ { "MD2", SEC_OID_MD2 },
+ { "MD5", SEC_OID_MD5 },
+ { "SHA1", SEC_OID_SHA1 },
+ { "SHA256", SEC_OID_SHA256 },
+ { "SHA384", SEC_OID_SHA384 },
+ { "SHA512", SEC_OID_SHA512 }
+ };
+
+ /* Maps a hash name to a SECOidTag.
+ * Returns NULL if the name is not a supported algorithm
+ */
+ static SECOidTag HashNameToOIDTag(const char *hashName)
+ {
+ int i, nhashes = sizeof(HASH_NAMES);
+ SECOidTag hashtag = SEC_OID_UNKNOWN;
+
+ for (i = 0; i < nhashes; i++) {
+ if (PORT_Strcasecmp(hashName, HASH_NAMES[i].hashName) == 0) {
+ hashtag = HASH_NAMES[i].oid;
+ break;
+ }
+ }
+ return hashtag;
+ }
+
+ /* Newline */
+ static void Newline(PRFileDesc* out)
+ {
+ PR_fprintf(out, "\n");
+ }
+
+ /* PrintAsHex */
+ void PrintAsHex(PRFileDesc* out, unsigned char *data, unsigned int len)
+ {
+ unsigned i;
+ int column;
+ unsigned int limit = 15;
+ unsigned int level = 1;
+
+ column = level;
+ if (!len) {
+ PR_fprintf(out, "(empty)\n");
+ return;
+ }
+
+ for (i = 0; i < len; i++) {
+ if (i != len - 1) {
+ PR_fprintf(out, "%02x:", data[i]);
+ column += 3;
+ } else {
+ PR_fprintf(out, "%02x", data[i]);
+ column += 2;
+ break;
+ }
+ if (column > 76 || (i % 16 == limit)) {
+ Newline(out);
+ column = level;
+ limit = i % 16;
+ }
+ }
+ if (column != level) {
+ Newline(out);
+ }
+ }
+
+
+ /* Prints a usage message and exits */
+ static void Usage(const char *progName)
+ {
+ int htype;
+ int HASH_AlgTOTAL = sizeof(HASH_NAMES) / sizeof(HASH_NAMES[0]);
+
+ fprintf(stderr, "Usage: %s -t type [ < input ] [ > output ]\n", progName);
+ fprintf(stderr, "%-20s Specify the digest method (must be one of\n",
+ "-t type");
+ fprintf(stderr, "%-20s ", "");
+ for (htype = 0; htype < HASH_AlgTOTAL; htype++) {
+ fprintf(stderr, HASH_NAMES[htype].hashName);
+ if (htype == (HASH_AlgTOTAL - 2))
+ fprintf(stderr, " or ");
+ else if (htype != (HASH_AlgTOTAL - 1))
+ fprintf(stderr, ", ");
+ }
+ fprintf(stderr, " (case ignored))\n");
+ fprintf(stderr, "%-20s Define an input file to use (default is stdin)\n",
+ "< input");
+ fprintf(stderr, "%-20s Define an output file to use (default is stdout)\n",
+ "> output");
+ exit(-1);
+ }
+
+ /* Check for the missing arguments */
+ static void
+ PrintMsgAndExit(const char *progName, char opt)
+ {
+ fprintf(stderr, "%s: option -%c requires an argument\n", progName, opt);
+ Usage(progName);
+ }
+
+ #define REQUIRE_ARG(opt,value) if (!(value)) PrintMsgAndExit(progName, opt)
+
+ /* Digests a file according to the specified algorithm.
+ * It writes out the digest as a hexadecimal string.
+ */
+ static int
+ DigestFile(PRFileDesc *outFile, PRFileDesc *inFile, SECOidTag hashOIDTag)
+ {
+ unsigned int nb;
+ unsigned char ibuf[4096];
+ unsigned char digest[64];
+ unsigned int len;
+ unsigned int digestLen;
+ HASH_HashType hashType;
+ HASHContext *hashContext = NULL;
+
+ hashType = HASH_GetHashTypeByOidTag(hashOIDTag);
+ hashContext = HASH_Create(hashType);
+ if (hashContext == NULL) {
+ return SECFailure;
+ }
+
+ do {
+ HASH_Begin(hashContext);
+
+ /* Incrementally hash the file contents */
+ while ((nb = PR_Read(inFile, ibuf, sizeof(ibuf))) > 0) {
+ HASH_Update(hashContext, ibuf, nb);
+ }
+
+ HASH_End(hashContext, digest, &len, 64);
+
+ /* Normally we would write it out in binary with
+ * nb = PR_Write(outFile, digest, len);
+ * but for illustration let's print it in hex.
+ */
+ PrintAsHex(outFile, digest, len);
+
+ } while (0);
+
+ /* cleanup */
+ if (hashContext != NULL)
+ HASH_Destroy(hashContext);
+
+ return SECSuccess;
+ }
+
+ /*
+ * This sample computes the hash of a file and saves it to another file. It illustrates the use of NSS message APIs.
+ */
+ int main(int argc, char **argv)
+ {
+ SECOidTag hashOIDTag;
+ PLOptState *optstate;
+ PLOptStatus status;
+ SECStatus rv;
+ char *hashName = NULL;
+ char *progName = strrchr(argv[0], '/');
+
+ progName = progName ? progName + 1 : argv[0];
+
+ rv = NSS_NoDB_Init("/tmp");
+ if (rv != SECSuccess) {
+ fprintf(stderr, "%s: NSS_Init failed in directory %s\n", progName, "/tmp");
+ return -1;
+ }
+
+ /* Parse command line arguments */
+ optstate = PL_CreateOptState(argc, argv, "t:");
+ while ((status = PL_GetNextOpt(optstate)) == PL_OPT_OK) {
+ switch (optstate->option) {
+ case 't':
+ REQUIRE_ARG(optstate->option, optstate->value);
+ hashName = strdup(optstate->value);
+ break;
+ }
+ }
+
+ if (!hashName)
+ Usage(progName);
+
+ /* convert and validate */
+ hashOIDTag = HashNameToOIDTag(hashName);
+ if (hashOIDTag == SEC_OID_UNKNOWN) {
+ fprintf(stderr, "%s: invalid digest type - %s\n", progName, hashName);
+ Usage(progName);
+ }
+
+ /* Digest it and print the result */
+ rv = DigestFile(PR_STDOUT, PR_STDIN, hashOIDTag);
+ if (rv != SECSuccess) {
+ fprintf(stderr, "%s: problem digesting data (%d)\n", progName, PORT_GetError());
+ }
+
+ rv = NSS_Shutdown();
+ if (rv != SECSuccess) {
+ exit(-1);
+ }
+
+ return 0;
+ } \ No newline at end of file
diff --git a/security/nss/doc/rst/legacy/nss_sample_code/sample1_-_hashing/index.rst b/security/nss/doc/rst/legacy/nss_sample_code/sample1_-_hashing/index.rst
new file mode 100644
index 0000000000..3fe6f2fb17
--- /dev/null
+++ b/security/nss/doc/rst/legacy/nss_sample_code/sample1_-_hashing/index.rst
@@ -0,0 +1,257 @@
+.. _mozilla_projects_nss_nss_sample_code_sample1_-_hashing:
+
+Hashing - sample 1
+==================
+
+.. _nss_sample_code_1_hashing.:
+
+`NSS sample code 1: hashing. <#nss_sample_code_1_hashing.>`__
+-------------------------------------------------------------
+
+.. container::
+
+ The NSS same code below computes the hash of a file and saves it to another file, this
+ illustrates the use of NSS message APIs.
+
+ .. 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 <prprf.h>
+ #include <prtypes.h>
+ #include <plgetopt.h>
+ #include <prio.h>
+
+ /* NSS headers */
+ #include <secoid.h>
+ #include <secmodt.h>
+ #include <sechash.h>
+ #include <nss.h>
+
+ typedef struct {
+ const char *hashName;
+ SECOidTag oid;
+ } NameTagPair;
+
+ /* The hash algorithms supported */
+ static const NameTagPair HASH_NAMES[] = {
+ { "MD2", SEC_OID_MD2 },
+ { "MD5", SEC_OID_MD5 },
+ { "SHA1", SEC_OID_SHA1 },
+ { "SHA256", SEC_OID_SHA256 },
+ { "SHA384", SEC_OID_SHA384 },
+ { "SHA512", SEC_OID_SHA512 }
+ };
+
+ /*
+ * Maps a hash name to a SECOidTag.
+ * Returns NULL if the name if not a supported algorithm
+ */
+ static SECOidTag HashNameToOIDTag(const char *hashName)
+ {
+ int i, nhashes = sizeof(HASH_NAMES);
+ SECOidTag hashtag = SEC_OID_UNKNOWN;
+
+ for (i = 0; i < nhashes; i++) {
+ if (PORT_Strcasecmp(hashName, HASH_NAMES[i].hashName) == 0) {
+ hashtag = HASH_NAMES[i].oid;
+ break;
+ }
+ }
+ return hashtag;
+ }
+
+ /*
+ * Newline
+ */
+ static void
+ Newline(PRFileDesc* out)
+ {
+ PR_fprintf(out, "\n");
+ }
+
+ /*
+ * PrintAsHex
+ */
+ void
+ PrintAsHex(PRFileDesc* out, unsigned char *data, unsigned int len)
+ {
+ unsigned i;
+ int column;
+ unsigned int limit = 15;
+ unsigned int level = 1;
+
+ column = level;
+ if (!len) {
+ PR_fprintf(out, "(empty)\n");
+ return;
+ }
+
+ for (i = 0; i < len; i++) {
+ if (i != len - 1) {
+ PR_fprintf(out, "%02x:", data[i]);
+ column += 3;
+ } else {
+ PR_fprintf(out, "%02x", data[i]);
+ column += 2;
+ break;
+ }
+ if (column > 76 || (i % 16 == limit)) {
+ Newline(out);
+ column = level;
+ limit = i % 16;
+ }
+ }
+ if (column != level) {
+ Newline(out);
+ }
+ }
+
+
+ /*
+ * Prints a usage message and exits
+ */
+ static void
+ Usage(const char *progName)
+ {
+ int htype;
+ int HASH_AlgTOTAL = sizeof(HASH_NAMES) / sizeof(HASH_NAMES[0]);
+
+ fprintf(stderr, "Usage: %s -t type [ < input ] [ > output ]\n", progName);
+ fprintf(stderr, "%-20s Specify the digest method (must be one of\n",
+ "-t type");
+ fprintf(stderr, "%-20s ", "");
+ for (htype = 0; htype < HASH_AlgTOTAL; htype++) {
+ fprintf(stderr, HASH_NAMES[htype].hashName);
+ if (htype == (HASH_AlgTOTAL - 2))
+ fprintf(stderr, " or ");
+ else if (htype != (HASH_AlgTOTAL - 1))
+ fprintf(stderr, ", ");
+ }
+ fprintf(stderr, " (case ignored))\n");
+ fprintf(stderr, "%-20s Define an input file to use (default is stdin)\n",
+ "< input");
+ fprintf(stderr, "%-20s Define an output file to use (default is stdout)\n",
+ "> output");
+ exit(-1);
+ }
+
+ /*
+ * Check for the missing arguments
+ */
+ static void
+ PrintMsgAndExit(const char *progName, char opt)
+ {
+ fprintf(stderr, "%s: option -%c requires an argument\n", progName, opt);
+ Usage(progName);
+ }
+
+ #define REQUIRE_ARG(opt,value) if (!(value)) PrintMsgAndExit(progName, opt)
+
+ /*
+ * Digests a file according to the specified algorithm.
+ * It writes out the digest as a hexadecimal string.
+ */
+ static int
+ DigestFile(PRFileDesc *outFile, PRFileDesc *inFile, SECOidTag hashOIDTag)
+ {
+ unsigned int nb;
+ unsigned char ibuf[4096];
+ unsigned char digest[64];
+ unsigned int len;
+ HASH_HashType hashType;
+ HASHContext *hashContext = NULL;
+
+ hashType = HASH_GetHashTypeByOidTag(hashOIDTag);
+ hashContext = HASH_Create(hashType);
+ if (hashContext == NULL) {
+ return SECFailure;
+ }
+
+ do {
+
+ HASH_Begin(hashContext);
+
+ /* Incrementally hash the file contents */
+ while ((nb = PR_Read(inFile, ibuf, sizeof(ibuf))) > 0) {
+ HASH_Update(hashContext, ibuf, nb);
+ }
+
+ HASH_End(hashContext, digest, &len, 64);
+
+ /* Normally we would write it out in binary with
+ * nb = PR_Write(outFile, digest, len);
+ * but for illustration let's print it in hex.
+ */
+ PrintAsHex(outFile, digest, len);
+
+ } while (0);
+
+ /* cleanup */
+ if (hashContext != NULL)
+ HASH_Destroy(hashContext);
+
+ return SECSuccess;
+ }
+
+ /*
+ * This sample computes the hash of a file and saves it
+ * to another file. It illustrates the use of NSS message
+ * APIs.
+ */
+ int main(int argc, char **argv)
+ {
+ SECOidTag hashOIDTag;
+ PLOptState *optstate;
+ PLOptStatus status;
+ SECStatus rv;
+ char *hashName = NULL;
+ char *progName = strrchr(argv[0], '/');
+
+ progName = progName ? progName + 1 : argv[0];
+
+ rv = NSS_NoDB_Init("/tmp");
+ if (rv != SECSuccess) {
+ fprintf(stderr, "%s: NSS_Init failed in directory %s\n",
+ progName, "/tmp");
+ return -1;
+ }
+
+ /* Parse command line arguments */
+ optstate = PL_CreateOptState(argc, argv, "t:");
+ while ((status = PL_GetNextOpt(optstate)) == PL_OPT_OK) {
+ switch (optstate->option) {
+ case 't':
+ REQUIRE_ARG(optstate->option, optstate->value);
+ hashName = strdup(optstate->value);
+ break;
+ }
+ }
+
+ if (!hashName)
+ Usage(progName);
+
+ /* convert and validate */
+ hashOIDTag = HashNameToOIDTag(hashName);
+ if (hashOIDTag == SEC_OID_UNKNOWN) {
+ fprintf(stderr, "%s: invalid digest type - %s\n", progName, hashName);
+ Usage(progName);
+ }
+
+ /* Digest it and print the result */
+ rv = DigestFile(PR_STDOUT, PR_STDIN, hashOIDTag);
+ if (rv != SECSuccess) {
+ fprintf(stderr, "%s: problem digesting data (%d)\n",
+ progName, PORT_GetError());
+ }
+
+ rv = NSS_Shutdown();
+ if (rv != SECSuccess) {
+ exit(-1);
+ }
+
+ return 0;
+ } \ No newline at end of file
diff --git a/security/nss/doc/rst/legacy/nss_sample_code/sample2/index.rst b/security/nss/doc/rst/legacy/nss_sample_code/sample2/index.rst
new file mode 100644
index 0000000000..5243b05e4d
--- /dev/null
+++ b/security/nss/doc/rst/legacy/nss_sample_code/sample2/index.rst
@@ -0,0 +1,12 @@
+.. _mozilla_projects_nss_nss_sample_code_sample2:
+
+sample2
+=======
+
+.. container::
+
+ .. container:: summary
+
+ .. 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 <cryptohi.h> #include <keyhi.h> #include <pk11priv.h> #include <cert.h> #include <base64.h> #include <secerr.h> #include <secport.h> #include <secoid.h> #include <secmodt.h> #include <secoidt.h> #include <sechash.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-----" /* Missing publically from nss versions earlier than 3.13 */ #ifndef SEC_ERROR_BASE #define SEC_ERROR_BASE (-0x2000) typedef enum { SEC_ERROR_IO = SEC_ERROR_BASE + 0, SEC_ERROR_TOKEN_NOT_LOGGED_IN = (SEC_ERROR_BASE + 155), SEC_ERROR_END_OF_LIST } SECErrorCodes; #endif /* PORT_ErrorToString introduced in nss 3.13. On earlier versions of nss that * don't support error tables, PR_ErrorToString will return "Unknown code". */ #ifndef PORT_ErrorToString #define PORT_ErrorToString(err) PR_ErrorToString((err), PR_LANGUAGE_I_DEFAULT) #endif /* 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; }</opfilename></encryptfilename></headerfilename></dbdirpath></ipfilename></headerfilename></dbdirpath></nickname></ipfilename></headerfilename></dbdirpath></nickname></encryptfilename></ipfilename></headerfilename></dbdirpath></headerfilename></nickname></dbdirpath></serialnumber></issuernickname></csr></cert></trust></nickname></dbdirpath></cert></trust></nickname></dbdirpath></csr></subject></dbdirpath></csr></issuernickname></trustargs></nickname></serialnumber></opfilename></encryptfilename></headerfilename></ipfilename></noisefilename></dbpwdfile></dbpwd></dbdirpath></ipfilename></headerfilename></infilename></headerfilename></opfilename></encryptfilename></headerfilename></encryptfilename></ipfilename></headerfilename></headerfilename></nickname></serialnumber></issuernickname></csr></cert></trust></nickname></csr></subject></opfilename></encryptfilename></headerfilename></ipfilename></headerfilename></ipfilename></headerfilename></encryptfilename></ipfilename></headerfilename></headerfilename></nickname></serialnumber></issuernickname></csr></cert></trust></nickname></csr></subject></noisefilename></dbpwdfile></dbpwd></dbdirpath></g|a|h|e|ds|v></sechash.h></secoidt.h></secmodt.h></secoid.h></secport.h></secerr.h></base64.h></cert.h></pk11priv.h></keyhi.h></cryptohi.h></plstr.h></prtypes.h></prlog.h></prinit.h></prerror.h></plgetopt.h></prthread.h>
diff --git a/security/nss/doc/rst/legacy/nss_sample_code/sample2_-_initialize_nss_database/index.rst b/security/nss/doc/rst/legacy/nss_sample_code/sample2_-_initialize_nss_database/index.rst
new file mode 100644
index 0000000000..fe1d83fc61
--- /dev/null
+++ b/security/nss/doc/rst/legacy/nss_sample_code/sample2_-_initialize_nss_database/index.rst
@@ -0,0 +1,250 @@
+.. _mozilla_projects_nss_nss_sample_code_sample2_-_initialize_nss_database:
+
+Initialize NSS database - sample 2
+==================================
+
+.. _nss_sample_code_2_initialize_the_nss_database.:
+
+`NSS sample code 2: initialize the NSS database. <#nss_sample_code_2_initialize_the_nss_database.>`__
+-----------------------------------------------------------------------------------------------------
+
+.. container::
+
+ The NSS sample code below demonstrates how to initialize the NSS database.
+
+ .. code:: c
+
+ /*
+ * Print a usage message and exit
+ */
+ static void
+ Usage(const char *progName)
+ {
+ fprintf(stderr, "\nUsage: %s -d [-p ]"
+ " [-f ]\n\n",
+ progName);
+ fprintf(stderr, "%-15s Specify a DB directory path\n\n",
+ "-d ");
+ fprintf(stderr, "%-15s Specify a plaintext password\n\n",
+ "-p ");
+ fprintf(stderr, "%-15s Specify a password file\n\n",
+ "-f ");
+ exit(-1);
+ }
+
+ /*
+ * InitSlotPassword
+ */
+ char *
+ InitSlotPassword(PK11SlotInfo *slot, PRBool retry, void *arg)
+ {
+ FILE *input;
+ FILE *output;
+ char *p0 = NULL;
+ char *p1 = NULL;
+ secuPWData *pwdata = (secuPWData *) arg;
+
+ if (pwdata->source == PW_FROMFILE) {
+ return FilePasswd(slot, retry, pwdata->data);
+ }
+ if (pwdata->source == PW_PLAINTEXT) {
+ return PL_strdup(pwdata->data);
+ }
+
+ /* open terminal */
+ input = fopen("/dev/tty", "r");
+ if (input == NULL) {
+ PR_fprintf(PR_STDERR, "Error opening input terminal for read\n");
+ return NULL;
+ }
+
+ /* we have no password, so initialize database with one */
+ PR_fprintf(PR_STDERR,
+ "Enter a password which will be used to encrypt your keys.\n"
+ "The password should be at least 8 characters long,\n"
+ "and should contain at least one non-alphabetic character.\n\n");
+
+ output = fopen("/dev/tty", "w");
+ if (output == NULL) {
+ PR_fprintf(PR_STDERR, "Error opening output terminal for write\n");
+ return NULL;
+ }
+
+ for (;;) {
+ if (p0)
+ PORT_Free(p0);
+ p0 = GetPassword(input, output, "Enter new password: ",
+ CheckPassword);
+ if (p1)
+ PORT_Free(p1);
+ p1 = GetPassword(input, output, "Re-enter password: ",
+ CheckPassword);
+ if (p0 && p1 && !PORT_Strcmp(p0, p1)) {
+ break;
+ }
+ PR_fprintf(PR_STDERR, "Passwords do not match. Try again.\n");
+ }
+
+ /* clear out the duplicate password string */
+ if (p1) {
+ PORT_Memset(p1, 0, PORT_Strlen(p1));
+ PORT_Free(p1);
+ }
+ fclose(input);
+ fclose(output);
+
+ return p0;
+ }
+
+ /*
+ * ChangePW
+ */
+ SECStatus
+ ChangePW(PK11SlotInfo *slot, char *oldPass, char *newPass,
+ char *oldPwFile, char *newPwFile)
+ {
+ SECStatus rv;
+ secuPWData pwdata;
+ secuPWData newpwdata;
+ char *oldpw = NULL;
+ char *newpw = NULL;
+
+ if (oldPass) {
+ pwdata.source = PW_PLAINTEXT;
+ pwdata.data = oldPass;
+ } else if (oldPwFile) {
+ pwdata.source = PW_FROMFILE;
+ pwdata.data = oldPwFile;
+ } else {
+ pwdata.source = PW_NONE;
+ pwdata.data = NULL;
+ }
+
+ if (newPass) {
+ newpwdata.source = PW_PLAINTEXT;
+ newpwdata.data = newPass;
+ } else if (newPwFile) {
+ newpwdata.source = PW_FROMFILE;
+ newpwdata.data = NULL;
+ } else {
+ newpwdata.source = PW_NONE;
+ newpwdata.data = NULL;
+ }
+
+ if (PK11_NeedUserInit(slot)) {
+ newpw = InitSlotPassword(slot, PR_FALSE, &pwdata);
+ rv = PK11_InitPin(slot, (char*)NULL, newpw);
+ if (rv == SECSuccess) {
+ PR_fprintf(PR_STDERR, "PK11_InitPin failed.\n");
+ return SECFailure;
+ }
+ }
+ else {
+ for (;;) {
+ oldpw = GetModulePassword(slot, PR_FALSE, &pwdata);
+
+ if (PK11_CheckUserPassword(slot, oldpw) != SECSuccess) {
+ if (pwdata.source == PW_NONE) {
+ PR_fprintf(PR_STDERR, "Invalid password. Try again.\n");
+ } else {
+ PR_fprintf(PR_STDERR, "Invalid password.\n");
+ PORT_Memset(oldpw, 0, PL_strlen(oldpw));
+ PORT_Free(oldpw);
+ return SECFailure;
+ }
+ } else {
+ break;
+ }
+ PORT_Free(oldpw);
+ }
+ newpw = InitSlotPassword(slot, PR_FALSE, &newpwdata);
+
+ if (PK11_ChangePW(slot, oldpw, newpw) != SECSuccess) {
+ PR_fprintf(PR_STDERR, "Failed to change password.\n");
+ return SECFailure;
+ }
+ PORT_Memset(oldpw, 0, PL_strlen(oldpw));
+ PORT_Free(oldpw);
+ PR_fprintf(PR_STDOUT, "Password changed successfully.\n");
+ }
+ PORT_Memset(newpw, 0, PL_strlen(newpw));
+ PORT_Free(newpw);
+ return SECSuccess;
+ }
+
+ /*
+ * This example illustrates initialization of the NSS database.
+ * It creates an nss configuration directory with empty databases
+ * and initializes the databases. It also illustrates techniques for
+ * password handling.
+ */
+ int main(int argc, char **argv)
+ {
+ PLOptState *optstate;
+ PLOptStatus status;
+ SECStatus rv;
+ SECStatus rvShutdown;
+ char *slotname = "internal";
+ PK11SlotInfo *slot = NULL;
+ char *dbdir = NULL;
+ char *plainPass = NULL;
+ char *pwFile = NULL;
+
+ char * progName = strrchr(argv[0], '/');
+ progName = progName ? progName + 1 : argv[0];
+
+ /* Parse command line arguments */
+ optstate = PL_CreateOptState(argc, argv, "d:p:q:f:g:");
+ while ((status = PL_GetNextOpt(optstate)) == PL_OPT_OK) {
+ switch (optstate->option) {
+ case 'd':
+ dbdir = strdup(optstate->value);
+ break;
+ case 'p':
+ plainPass = strdup(optstate->value);
+ break;
+ case 'f':
+ pwFile = strdup(optstate->value);
+ break;
+ default:
+ Usage(progName);
+ break;
+ }
+ }
+ PL_DestroyOptState(optstate);
+
+ if (!dbdir)
+ Usage(progName);
+
+ PR_Init(PR_USER_THREAD, PR_PRIORITY_NORMAL, 0);
+
+ /* Create the database */
+ rv = NSS_InitReadWrite(dbdir);
+ if (rv != SECSuccess) {
+ PR_fprintf(PR_STDERR, "NSS_Initialize Failed");
+ PR_Cleanup();
+ exit(rv);
+ }
+
+ if (PL_strcmp(slotname, "internal") == 0)
+ slot = PK11_GetInternalKeySlot();
+
+ /* If creating new database, initialize the password. */
+ rv = ChangePW(slot, plainPass, 0, pwFile, 0);
+ if (rv != SECSuccess) {
+ PR_fprintf(PR_STDERR, "Failed to change password\n");
+ }
+
+ if (slot) {
+ PK11_FreeSlot(slot);
+ }
+ rvShutdown = NSS_Shutdown();
+ if (rvShutdown != SECSuccess) {
+ PR_fprintf(PR_STDERR, "Failed : NSS_Shutdown()\n");
+ rv = SECFailure;
+ }
+
+ PR_Cleanup();
+
+ return rv;
+ } \ No newline at end of file
diff --git a/security/nss/doc/rst/legacy/nss_sample_code/sample3_-_encdecmac_using_token_object/index.rst b/security/nss/doc/rst/legacy/nss_sample_code/sample3_-_encdecmac_using_token_object/index.rst
new file mode 100644
index 0000000000..ec6ff208fb
--- /dev/null
+++ b/security/nss/doc/rst/legacy/nss_sample_code/sample3_-_encdecmac_using_token_object/index.rst
@@ -0,0 +1,30 @@
+.. _mozilla_projects_nss_nss_sample_code_sample3_-_encdecmac_using_token_object:
+
+EncDecMAC using token object - sample 3
+=======================================
+
+.. _encdecmac_using_token_object:
+
+`EncDecMAC using token object <#encdecmac_using_token_object>`__
+----------------------------------------------------------------
+
+.. container::
+
+`Example: <#example>`__
+~~~~~~~~~~~~~~~~~~~~~~~
+
+.. container::
+
+.. _nss_sample_code_3_hashing.:
+
+`NSS Sample Code 3: Enc/Dec/MAC Using Token Object ID. <#nss_sample_code_3_hashing.>`__
+---------------------------------------------------------------------------------------
+
+.. container::
+
+ Computes the hash of a file and saves it to another file, illustrates the use of NSS message
+ APIs.
+
+ .. 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 #include #include #include #include #include #include /* NSS headers */ #include #include /* our samples utilities */ #include "util.h" #define BUFFERSIZE 80 #define DIGESTSIZE 16 #define PTEXT_MAC_BUFFER_SIZE 96 #define CIPHERSIZE 96 #define BLOCKSIZE 32 #define CIPHER_HEADER "-----BEGIN CIPHER-----" #define CIPHER_TRAILER "-----END CIPHER-----" #define ENCKEY_HEADER "-----BEGIN AESKEY CKAID-----" #define ENCKEY_TRAILER "-----END AESKEY CKAID-----" #define MACKEY_HEADER "-----BEGIN MACKEY CKAID-----" #define MACKEY_TRAILER "-----END MACKEY CKAID-----" #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-----" typedef enum { ENCRYPT, DECRYPT, UNKNOWN } CommandType; typedef enum { SYMKEY = 0, MACKEY = 1, IV = 2, MAC = 3, PAD = 4 } HeaderType; /* * Print usage message and exit */ static void Usage(const char *progName) { fprintf(stderr, "\nUsage: %s -c -d [-z ] " "[-p | -f ] -i -o \n\n", progName); fprintf(stderr, "%-20s Specify 'a' for encrypt operation\n\n", "-c "); fprintf(stderr, "%-20s Specify 'b' for decrypt operation\n\n", " "); fprintf(stderr, "%-20s Specify db directory path\n\n", "-d "); fprintf(stderr, "%-20s Specify db password [optional]\n\n", "-p "); fprintf(stderr, "%-20s Specify db password file [optional]\n\n", "-f "); fprintf(stderr, "%-20s Specify noise file name [optional]\n\n", "-z "); fprintf(stderr, "%-21s Specify an input file name\n\n", "-i "); fprintf(stderr, "%-21s Specify an output file name\n\n", "-o "); fprintf(stderr, "%-7s For encrypt, it takes as an input file and produces\n", "Note :"); fprintf(stderr, "%-7s .enc and .header as intermediate output files.\n\n", ""); fprintf(stderr, "%-7s For decrypt, it takes .enc and .header\n", ""); fprintf(stderr, "%-7s as input files and produces as a final output file.\n\n", ""); exit(-1); } /* * Gather a CKA_ID */ SECStatus GatherCKA_ID(PK11SymKey* key, SECItem* buf) { SECStatus rv = PK11_ReadRawAttribute(PK11_TypeSymKey, key, CKA_ID, buf); if (rv != SECSuccess) { PR_fprintf(PR_STDERR, "PK11_ReadRawAttribute returned (%d)\n", rv); PR_fprintf(PR_STDERR, "Could not read SymKey CKA_ID attribute\n"); return rv; } return rv; } /* * Generate a Symmetric Key */ PK11SymKey * GenerateSYMKey(PK11SlotInfo *slot, CK_MECHANISM_TYPE mechanism, int keySize, SECItem *keyID, secuPWData *pwdata) { SECStatus rv; PK11SymKey *key; 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)); return NULL; } } /* Generate the symmetric key */ key = PK11_TokenKeyGen(slot, mechanism, NULL, keySize, keyID, PR_TRUE, pwdata); if (!key) { PR_fprintf(PR_STDERR, "Symmetric Key Generation Failed \n"); } return key; } /* * MacInit */ SECStatus MacInit(PK11Context *ctx) { SECStatus rv = PK11_DigestBegin(ctx); if (rv != SECSuccess) { PR_fprintf(PR_STDERR, "Compute MAC Failed : PK11_DigestBegin()\n"); } return rv; } /* * MacUpdate */ SECStatus MacUpdate(PK11Context *ctx, unsigned char *msg, unsigned int msgLen) { SECStatus rv = PK11_DigestOp(ctx, msg, msgLen); if (rv != SECSuccess) { PR_fprintf(PR_STDERR, "Compute MAC Failed : DigestOp()\n"); } return rv; } /* * Finalize MACing */ SECStatus MacFinal(PK11Context *ctx, unsigned char *mac, unsigned int *macLen, unsigned int maxLen) { SECStatus rv = PK11_DigestFinal(ctx, mac, macLen, maxLen); if (rv != SECSuccess) { PR_fprintf(PR_STDERR, "Compute MAC Failed : PK11_DigestFinal()\n"); } return SECSuccess; } /* * Compute Mac */ SECStatus ComputeMac(PK11Context *ctxmac, unsigned char *ptext, unsigned int ptextLen, unsigned char *mac, unsigned int *macLen, unsigned int maxLen) { SECStatus rv = MacInit(ctxmac); if (rv != SECSuccess) return rv; rv = MacUpdate(ctxmac, ptext, ptextLen); if (rv != SECSuccess) return rv; rv = MacFinal(ctxmac, mac, macLen, maxLen); return rv; } /* * WriteToHeaderFile */ SECStatus WriteToHeaderFile(const char *buf, unsigned int len, HeaderType type, PRFileDesc *outFile) { SECStatus rv; char header[40]; char trailer[40]; char *outString = NULL; switch (type) { case SYMKEY: strcpy(header, ENCKEY_HEADER); strcpy(trailer, ENCKEY_TRAILER); break; case MACKEY: strcpy(header, MACKEY_HEADER); strcpy(trailer, MACKEY_TRAILER); break; case IV: strcpy(header, IV_HEADER); strcpy(trailer, IV_TRAILER); break; case MAC: strcpy(header, MAC_HEADER); strcpy(trailer, MAC_TRAILER); break; case PAD: strcpy(header, PAD_HEADER); strcpy(trailer, PAD_TRAILER); break; } PR_fprintf(outFile, "%s\n", header); PrintAsHex(outFile, buf, len); PR_fprintf(outFile, "%s\n\n", trailer); return SECSuccess; } /* * Initialize for encryption or decryption - common code */ PK11Context * CryptInit(PK11SymKey *key, unsigned char *iv, unsigned int ivLen, CK_MECHANISM_TYPE type, CK_ATTRIBUTE_TYPE operation) { SECItem ivItem = { siBuffer, iv, ivLen }; PK11Context *ctx = NULL; SECItem *secParam = PK11_ParamFromIV(CKM_AES_CBC, &ivItem); if (secParam == NULL) { PR_fprintf(PR_STDERR, "Crypt Failed : secParam NULL\n"); return NULL; } ctx = PK11_CreateContextBySymKey(CKM_AES_CBC, operation, key, secParam); if (ctx == NULL) { PR_fprintf(PR_STDERR, "Crypt Failed : can't create a context\n"); goto cleanup; } cleanup: if (secParam) { SECITEM_FreeItem(secParam, PR_TRUE); } return ctx; } /* * Common encryption and decryption code */ SECStatus Crypt(PK11Context *ctx, unsigned char *out, unsigned int *outLen, unsigned int maxOut, unsigned char *in, unsigned int inLen) { SECStatus rv; rv = PK11_CipherOp(ctx, out, outLen, maxOut, in, inLen); if (rv != SECSuccess) { PR_fprintf(PR_STDERR, "Crypt Failed : PK11_CipherOp returned %d\n", rv); goto cleanup; } cleanup: if (rv != SECSuccess) { return rv; } return SECSuccess; } /* * Decrypt */ SECStatus Decrypt(PK11Context *ctx, unsigned char *out, unsigned int *outLen, unsigned int maxout, unsigned char *in, unsigned int inLen) { return Crypt(ctx, out, outLen, maxout, in, inLen); } /* * Encrypt */ SECStatus Encrypt(PK11Context* ctx, unsigned char *out, unsigned int *outLen, unsigned int maxout, unsigned char *in, unsigned int inLen) { return Crypt(ctx, out, outLen, maxout, in, inLen); } /* * EncryptInit */ PK11Context * EncryptInit(PK11SymKey *ek, unsigned char *iv, unsigned int ivLen, CK_MECHANISM_TYPE type) { return CryptInit(ek, iv, ivLen, type, CKA_ENCRYPT); } /* * DecryptInit */ PK11Context * DecryptInit(PK11SymKey *dk, unsigned char *iv, unsigned int ivLen, CK_MECHANISM_TYPE type) { return CryptInit(dk, iv, ivLen, type, CKA_DECRYPT); } /* * Read cryptographic parameters from the header file */ SECStatus ReadFromHeaderFile(const char *fileName, HeaderType type, SECItem *item, PRBool isHexData) { SECStatus rv; PRFileDesc* file; SECItem filedata; SECItem outbuf; unsigned char *nonbody; unsigned char *body; char header[40]; char trailer[40]; outbuf.type = siBuffer; file = PR_Open(fileName, PR_RDONLY, 0); if (!file) { PR_fprintf(PR_STDERR, "Failed to open %s\n", fileName); return SECFailure; } switch (type) { case SYMKEY: strcpy(header, ENCKEY_HEADER); strcpy(trailer, ENCKEY_TRAILER); break; case MACKEY: strcpy(header, MACKEY_HEADER); strcpy(trailer, MACKEY_TRAILER); break; case IV: strcpy(header, IV_HEADER); strcpy(trailer, IV_TRAILER); break; case MAC: strcpy(header, MAC_HEADER); strcpy(trailer, MAC_TRAILER); break; case PAD: strcpy(header, PAD_HEADER); strcpy(trailer, PAD_TRAILER); break; } 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); return SECFailure; } } else { body = nonbody; } cleanup: PR_Close(file); HexToBuf(body, item, isHexData); return SECSuccess; } /* * EncryptAndMac */ SECStatus EncryptAndMac(PRFileDesc *inFile, PRFileDesc *headerFile, PRFileDesc *encFile, PK11SymKey *ek, PK11SymKey *mk, unsigned char *iv, unsigned int ivLen, PRBool ascii) { SECStatus rv; unsigned char ptext[BLOCKSIZE]; unsigned int ptextLen; unsigned char mac[DIGESTSIZE]; unsigned int macLen; unsigned int nwritten; unsigned char encbuf[BLOCKSIZE]; unsigned int encbufLen; SECItem noParams = { siBuffer, NULL, 0 }; PK11Context *ctxmac = NULL; PK11Context *ctxenc = NULL; unsigned int pad[1]; SECItem padItem; unsigned int paddingLength; static unsigned int firstTime = 1; int j; ctxmac = PK11_CreateContextBySymKey(CKM_MD5_HMAC, CKA_SIGN, mk, &noParams); if (ctxmac == NULL) { PR_fprintf(PR_STDERR, "Can't create MAC context\n"); rv = SECFailure; goto cleanup; } rv = MacInit(ctxmac); if (rv != SECSuccess) { goto cleanup; } ctxenc = EncryptInit(ek, iv, ivLen, CKM_AES_CBC); /* read a buffer of plaintext from input file */ while ((ptextLen = PR_Read(inFile, ptext, sizeof(ptext))) > 0) { /* Encrypt using it using CBC, using previously created IV */ if (ptextLen != BLOCKSIZE) { paddingLength = BLOCKSIZE - ptextLen; for ( j=0; j < paddingLength; j++) { ptext[ptextLen+j] = (unsigned char)paddingLength; } ptextLen = BLOCKSIZE; } rv = Encrypt(ctxenc, encbuf, &encbufLen, sizeof(encbuf), ptext, ptextLen); if (rv != SECSuccess) { PR_fprintf(PR_STDERR, "Encrypt Failure\n"); goto cleanup; } /* save the last block of ciphertext as the next IV */ iv = encbuf; ivLen = encbufLen; /* write the cipher text to intermediate file */ nwritten = PR_Write(encFile, encbuf, encbufLen); /*PR_Assert(nwritten == encbufLen);*/ rv = MacUpdate(ctxmac, ptext, ptextLen); } rv = MacFinal(ctxmac, mac, &macLen, DIGESTSIZE); if (rv != SECSuccess) { PR_fprintf(PR_STDERR, "MacFinal Failure\n"); goto cleanup; } if (macLen == 0) { PR_fprintf(PR_STDERR, "Bad MAC length\n"); rv = SECFailure; goto cleanup; } WriteToHeaderFile(mac, macLen, MAC, headerFile); if (rv != SECSuccess) { PR_fprintf(PR_STDERR, "Write MAC Failure\n"); goto cleanup; } pad[0] = paddingLength; padItem.type = siBuffer; padItem.data = (unsigned char *)pad; padItem.len = sizeof(pad[0]); WriteToHeaderFile(padItem.data, padItem.len, PAD, headerFile); if (rv != SECSuccess) { PR_fprintf(PR_STDERR, "Write PAD Failure\n"); goto cleanup; } rv = SECSuccess; cleanup: if (ctxmac != NULL) { PK11_DestroyContext(ctxmac, PR_TRUE); } if (ctxenc != NULL) { PK11_DestroyContext(ctxenc, PR_TRUE); } return rv; } /* * Find the Key for the given mechanism */ PK11SymKey* FindKey(PK11SlotInfo *slot, CK_MECHANISM_TYPE mechanism, SECItem *keyBuf, secuPWData *pwdata) { SECStatus rv; PK11SymKey *key; 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)); if (slot) { PK11_FreeSlot(slot); } return NULL; } } key = PK11_FindFixedKey(slot, mechanism, keyBuf, 0); if (!key) { PR_fprintf(PR_STDERR, "PK11_FindFixedKey failed (err %d)\n", PR_GetError()); PK11_FreeSlot(slot); return NULL; } return key; } /* * Decrypt and Verify MAC */ SECStatus DecryptAndVerifyMac(const char* outFileName, char *encryptedFileName, SECItem *cItem, SECItem *macItem, PK11SymKey* ek, PK11SymKey* mk, SECItem *ivItem, SECItem *padItem) { SECStatus rv; PRFileDesc* inFile; PRFileDesc* outFile; unsigned char decbuf[64]; unsigned int decbufLen; unsigned char ptext[BLOCKSIZE]; unsigned int ptextLen = 0; unsigned char ctext[64]; unsigned int ctextLen; unsigned char newmac[DIGESTSIZE]; unsigned int newmacLen = 0; unsigned int newptextLen = 0; unsigned int count = 0; unsigned int temp = 0; unsigned int blockNumber = 0; SECItem noParams = { siBuffer, NULL, 0 }; PK11Context *ctxmac = NULL; PK11Context *ctxenc = NULL; unsigned char iv[BLOCKSIZE]; unsigned int ivLen = ivItem->len; unsigned int fileLength; unsigned int paddingLength; int j; memcpy(iv, ivItem->data, ivItem->len); paddingLength = (unsigned int)padItem->data[0]; ctxmac = PK11_CreateContextBySymKey(CKM_MD5_HMAC, CKA_SIGN, mk, &noParams); if (ctxmac == NULL) { PR_fprintf(PR_STDERR, "Can't create MAC context\n"); rv = SECFailure; goto cleanup; } /* Open the input file. */ inFile = PR_Open(encryptedFileName, PR_RDONLY , 0); if (!inFile) { PR_fprintf(PR_STDERR, "Unable to open \"%s\" for writing.\n", encryptedFileName); return SECFailure; } /* Open the output file. */ 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); return SECFailure; } rv = MacInit(ctxmac); if (rv != SECSuccess) goto cleanup; ctxenc = DecryptInit(ek, iv, ivLen, CKM_AES_CBC); fileLength = FileSize(encryptedFileName); while ((ctextLen = PR_Read(inFile, ctext, sizeof(ctext))) > 0) { count += ctextLen; /* decrypt cipher text buffer using CBC and IV */ rv = Decrypt(ctxenc, decbuf, &decbufLen, sizeof(decbuf), ctext, ctextLen); if (rv != SECSuccess) { PR_fprintf(PR_STDERR, "Decrypt Failure\n"); goto cleanup; } if (decbufLen == 0) break; rv = MacUpdate(ctxmac, decbuf, decbufLen); if (rv != SECSuccess) { goto cleanup; } if (count == fileLength) { 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; } /* save last block of ciphertext */ memcpy(iv, decbuf, decbufLen); ivLen = decbufLen; blockNumber++; } if (rv != SECSuccess) { goto cleanup; } rv = MacFinal(ctxmac, newmac, &newmacLen, sizeof(newmac)); if (rv != SECSuccess) { goto cleanup; } if (PORT_Memcmp(macItem->data, newmac, newmacLen) == 0) { rv = SECSuccess; } else { PR_fprintf(PR_STDERR, "Check MAC : Failure\n"); PR_fprintf(PR_STDERR, "Extracted : "); PrintAsHex(PR_STDERR, macItem->data, macItem->len); PR_fprintf(PR_STDERR, "Computed : "); PrintAsHex(PR_STDERR, newmac, newmacLen); rv = SECFailure; } cleanup: if (ctxmac) { PK11_DestroyContext(ctxmac, PR_TRUE); } if (ctxenc) { PK11_DestroyContext(ctxenc, PR_TRUE); } if (outFile) { PR_Close(outFile); } return rv; } /* * Gets IV and CKAIDS From Header File */ SECStatus GetIVandCKAIDSFromHeader(const char *cipherFileName, SECItem *ivItem, SECItem *encKeyItem, SECItem *macKeyItem) { SECStatus rv; /* open intermediate file, read in header, get IV and CKA_IDs of two keys * from it */ rv = ReadFromHeaderFile(cipherFileName, IV, ivItem, PR_TRUE); if (rv != SECSuccess) { PR_fprintf(PR_STDERR, "Could not retrieve IV from cipher file\n"); goto cleanup; } rv = ReadFromHeaderFile(cipherFileName, SYMKEY, encKeyItem, PR_TRUE); if (rv != SECSuccess) { PR_fprintf(PR_STDERR, "Could not retrieve AES CKA_ID from cipher file\n"); goto cleanup; } rv = ReadFromHeaderFile(cipherFileName, MACKEY, macKeyItem, PR_TRUE); if (rv != SECSuccess) { PR_fprintf(PR_STDERR, "Could not retrieve MAC CKA_ID from cipher file\n"); goto cleanup; } cleanup: return rv; } /* * DecryptFile */ SECStatus DecryptFile(PK11SlotInfo *slot, const char *dbdir, const char *outFileName, const char *headerFileName, char *encryptedFileName, secuPWData *pwdata, PRBool ascii) { /* * The DB is open read only and we have authenticated to it * open input file, read in header, get IV and CKA_IDs of two keys from it * find those keys in the DB token * Open output file * loop until EOF(input): * read a buffer of ciphertext from input file, * Save last block of ciphertext * decrypt ciphertext buffer using CBC and IV, * compute and check MAC, then remove MAC from plaintext * replace IV with saved last block of ciphertext * write the plain text to output file * close files * report success */ SECStatus rv; SECItem ivItem; SECItem encKeyItem; SECItem macKeyItem; SECItem cipherItem; SECItem macItem; SECItem padItem; PK11SymKey *encKey = NULL; PK11SymKey *macKey = NULL; /* open intermediate file, read in header, get IV and CKA_IDs of two keys * from it */ rv = GetIVandCKAIDSFromHeader(headerFileName, &ivItem, &encKeyItem, &macKeyItem); if (rv != SECSuccess) { goto cleanup; } /* find those keys in the DB token */ encKey = FindKey(slot, CKM_AES_CBC, &encKeyItem, pwdata); if (encKey == NULL) { PR_fprintf(PR_STDERR, "Can't find the encryption key\n"); rv = SECFailure; goto cleanup; } /* CKM_MD5_HMAC or CKM_EXTRACT_KEY_FROM_KEY */ macKey = FindKey(slot, CKM_MD5_HMAC, &macKeyItem, pwdata); if (macKey == NULL) { rv = SECFailure; goto cleanup; } /* Read in the Mac into item from the intermediate file */ rv = ReadFromHeaderFile(headerFileName, MAC, &macItem, PR_TRUE); if (rv != SECSuccess) { PR_fprintf(PR_STDERR, "Could not retrieve MAC from cipher file\n"); goto cleanup; } if (macItem.data == NULL) { PR_fprintf(PR_STDERR, "MAC has NULL data\n"); rv = SECFailure; goto cleanup; } if (macItem.len == 0) { PR_fprintf(PR_STDERR, "MAC has data has 0 length\n"); /*rv = SECFailure; goto cleanup;*/ } 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; } if (rv == SECSuccess) { /* Decrypt and Remove Mac */ rv = DecryptAndVerifyMac(outFileName, encryptedFileName, &cipherItem, &macItem, encKey, macKey, &ivItem, &padItem); if (rv != SECSuccess) { PR_fprintf(PR_STDERR, "Failed while decrypting and removing MAC\n"); } } cleanup: if (slot) { PK11_FreeSlot(slot); } if (encKey) { PK11_FreeSymKey(encKey); } if (macKey) { PK11_FreeSymKey(macKey); } return rv; } /* * EncryptFile */ SECStatus EncryptFile(PK11SlotInfo *slot, const char *dbdir, const char *inFileName, const char *headerFileName, const char *encryptedFileName, const char *noiseFileName, secuPWData *pwdata, PRBool ascii) { /* * The DB is open for read/write and we have authenticated to it. * generate a symmetric AES key as a token object. * generate a second key to use for MACing, also a token object. * get their CKA_IDs * generate a random value to use as IV for AES CBC * open an input file and an output file, * write a header to the output that identifies the two keys by * their CKA_IDs, May include original file name and length. * loop until EOF(input) * read a buffer of plaintext from input file, * MAC it, append the MAC to the plaintext * encrypt it using CBC, using previously created IV, * store the last block of ciphertext as the new IV, * write the cipher text to intermediate file * close files * report success */ SECStatus rv; PRFileDesc *inFile; PRFileDesc *headerFile; PRFileDesc *encFile; unsigned char *encKeyId = (unsigned char *) "Encrypt Key"; unsigned char *macKeyId = (unsigned char *) "MAC Key"; SECItem encKeyID = { siAsciiString, encKeyId, PL_strlen(encKeyId) }; SECItem macKeyID = { siAsciiString, macKeyId, PL_strlen(macKeyId) }; SECItem encCKAID; SECItem macCKAID; unsigned char iv[BLOCKSIZE]; SECItem ivItem; PK11SymKey *encKey = NULL; PK11SymKey *macKey = NULL; SECItem temp; unsigned char c; /* generate a symmetric AES key as a token object. */ encKey = GenerateSYMKey(slot, CKM_AES_KEY_GEN, 128/8, &encKeyID, pwdata); if (encKey == NULL) { PR_fprintf(PR_STDERR, "GenerateSYMKey for AES returned NULL.\n"); rv = SECFailure; goto cleanup; } /* generate a second key to use for MACing, also a token object. */ macKey = GenerateSYMKey(slot, CKM_GENERIC_SECRET_KEY_GEN, 160/8, &macKeyID, pwdata); if (macKey == NULL) { PR_fprintf(PR_STDERR, "GenerateSYMKey for MACing returned NULL.\n"); rv = SECFailure; goto cleanup; } /* get the encrypt key CKA_ID */ rv = GatherCKA_ID(encKey, &encCKAID); if (rv != SECSuccess) { PR_fprintf(PR_STDERR, "Error while wrapping encrypt key\n"); goto cleanup; } /* get the MAC key CKA_ID */ rv = GatherCKA_ID(macKey, &macCKAID); if (rv != SECSuccess) { PR_fprintf(PR_STDERR, "Can't get the MAC key CKA_ID.\n"); goto cleanup; } if (noiseFileName) { rv = SeedFromNoiseFile(noiseFileName); if (rv != SECSuccess) { PORT_SetError(PR_END_OF_FILE_ERROR); return SECFailure; } rv = PK11_GenerateRandom(iv, BLOCKSIZE); if (rv != SECSuccess) { goto cleanup; } } else { /* generate a random value to use as IV for AES CBC */ GenerateRandom(iv, BLOCKSIZE); } headerFile = PR_Open(headerFileName, PR_CREATE_FILE | PR_TRUNCATE | PR_RDWR, 00660); if (!headerFile) { PR_fprintf(PR_STDERR, "Unable to open \"%s\" for writing.\n", headerFileName); return SECFailure; } 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); return SECFailure; } /* write to a header file the IV and the CKA_IDs * identifying the two keys */ ivItem.type = siBuffer; ivItem.data = iv; ivItem.len = BLOCKSIZE; rv = WriteToHeaderFile(iv, BLOCKSIZE, IV, headerFile); if (rv != SECSuccess) { PR_fprintf(PR_STDERR, "Error writing IV to cipher file - %s\n", headerFileName); goto cleanup; } rv = WriteToHeaderFile(encCKAID.data, encCKAID.len, SYMKEY, headerFile); if (rv != SECSuccess) { PR_fprintf(PR_STDERR, "Error writing AES CKA_ID to cipher file - %s\n", encryptedFileName); goto cleanup; } rv = WriteToHeaderFile(macCKAID.data, macCKAID.len, MACKEY, headerFile); if (rv != SECSuccess) { PR_fprintf(PR_STDERR, "Error writing MAC CKA_ID to cipher file - %s\n", headerFileName); goto cleanup; } /* 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); return SECFailure; } /* Macing and Encryption */ if (rv == SECSuccess) { rv = EncryptAndMac(inFile, headerFile, encFile, encKey, macKey, ivItem.data, ivItem.len, ascii); if (rv != SECSuccess) { PR_fprintf(PR_STDERR, "Failed : Macing and Encryption\n"); goto cleanup; } } cleanup: if (inFile) { PR_Close(inFile); } if (headerFile) { PR_Close(headerFile); } if (encFile) { PR_Close(encFile); } if (slot) { PK11_FreeSlot(slot); } if (encKey) { PK11_FreeSymKey(encKey); } if (macKey) { PK11_FreeSymKey(macKey); } return rv; } /* * This example illustrates basic encryption/decryption and MACing * Generates the encryption/mac keys and uses token for storing. * Encrypts the input file and appends MAC before storing in intermediate * header file. * Writes the CKA_IDs of the encryption keys into intermediate header file. * Reads the intermediate headerfile for CKA_IDs and encrypted * contents and decrypts into output file. */ int main(int argc, char **argv) { SECStatus rv; SECStatus rvShutdown; PK11SlotInfo *slot = NULL; PLOptState *optstate; PLOptStatus status; char headerFileName[50]; char encryptedFileName[50]; PRFileDesc *inFile; PRFileDesc *outFile; PRBool ascii = PR_FALSE; CommandType cmd = UNKNOWN; const char *command = NULL; const char *dbdir = NULL; const char *inFileName = NULL; const char *outFileName = NULL; const char *noiseFileName = NULL; secuPWData pwdata = { PW_NONE, 0 }; char * progName = strrchr(argv[0], '/'); progName = progName ? progName + 1 : argv[0]; /* Parse command line arguments */ optstate = PL_CreateOptState(argc, argv, "c:d:i:o:f:p:z:a"); while ((status = PL_GetNextOpt(optstate)) == PL_OPT_OK) { switch (optstate->option) { case 'a': ascii = PR_TRUE; break; case 'c': command = strdup(optstate->value); 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 'o': outFileName = strdup(optstate->value); break; case 'z': noiseFileName = strdup(optstate->value); break; default: Usage(progName); break; } } PL_DestroyOptState(optstate); if (!command || !dbdir || !inFileName || !outFileName) Usage(progName); if (PL_strlen(command)==0) Usage(progName); cmd = command[0] == 'a' ? ENCRYPT : command[0] == 'b' ? DECRYPT : UNKNOWN; /* 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); return SECFailure; } PR_Close(inFile); /* For intermediate header file, choose filename as inputfile name with extension ".header" */ strcpy(headerFileName, inFileName); strcat(headerFileName, ".header"); /* For intermediate encrypted file, choose filename as inputfile name with extension ".enc" */ strcpy(encryptedFileName, inFileName); strcat(encryptedFileName, ".enc"); PR_Init(PR_USER_THREAD, PR_PRIORITY_NORMAL, 0); switch (cmd) { case ENCRYPT: /* If the intermediate header file already exists, delete it */ if (PR_Access(headerFileName, PR_ACCESS_EXISTS) == PR_SUCCESS) { PR_Delete(headerFileName); } /* If the intermediate encrypted already exists, delete it */ if (PR_Access(encryptedFileName, PR_ACCESS_EXISTS) == PR_SUCCESS) { PR_Delete(encryptedFileName); } /* Open DB for read/write and authenticate to it. */ 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; } } rv = EncryptFile(slot, dbdir, inFileName, headerFileName, encryptedFileName, noiseFileName, &pwdata, ascii); if (rv != SECSuccess) { PR_fprintf(PR_STDERR, "EncryptFile : Failed\n"); return SECFailure; } break; case DECRYPT: /* Open DB read only, authenticate to it */ PK11_SetPasswordFunc(GetModulePassword); rv = NSS_Init(dbdir); if (rv != SECSuccess) { PR_fprintf(PR_STDERR, "NSS_Init Failed\n"); return SECFailure; } 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; } } rv = DecryptFile(slot, dbdir, outFileName, headerFileName, encryptedFileName, &pwdata, ascii); if (rv != SECSuccess) { PR_fprintf(PR_STDERR, "DecryptFile : Failed\n"); return SECFailure; } break; } cleanup: rvShutdown = NSS_Shutdown(); if (rvShutdown != SECSuccess) { PR_fprintf(PR_STDERR, "Failed : NSS_Shutdown()\n"); rv = SECFailure; } PR_Cleanup(); return rv; } \ No newline at end of file
diff --git a/security/nss/doc/rst/legacy/nss_sample_code/utiltiies_for_nss_samples/index.rst b/security/nss/doc/rst/legacy/nss_sample_code/utiltiies_for_nss_samples/index.rst
new file mode 100644
index 0000000000..a1df68437e
--- /dev/null
+++ b/security/nss/doc/rst/legacy/nss_sample_code/utiltiies_for_nss_samples/index.rst
@@ -0,0 +1,747 @@
+.. _mozilla_projects_nss_nss_sample_code_utiltiies_for_nss_samples:
+
+Utilities for nss samples
+=========================
+
+.. _nss_sample_code_0_utilities.:
+
+`NSS Sample Code 0: Utilities. <#nss_sample_code_0_utilities.>`__
+-----------------------------------------------------------------
+
+.. container::
+
+ These utility functions are adapted from those found in the sectool library used by the NSS
+ security tools and other NSS test applications.
+
+ It shows the following:
+
+ - Read DER from a file.
+ - Compile file size.
+ - Get seed From a noise gile.
+ - Generate random numbers.
+ - Get a module password.
+ - Extract the password from a text file.
+ - Print data as hexadecimal.
+
+`util.h <#util.h>`__
+~~~~~~~~~~~~~~~~~~~~
+
+.. container::
+
+ .. 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/. */
+
+ #ifndef _UTIL_H
+ #define _UTIL_H
+
+ #include <prlog.h>
+ #include <termios.h>
+ #include <base64.h>
+ #include <unistd.h>
+ #include <sys/stat.h>
+ #include "util.h"
+ #include <prprf.h>
+ #include <prerror.h>
+ #include <nss.h>
+ #include <pk11func.h>
+
+ /*
+ * These utility functions are adapted from those found in
+ * the sectool library used by the NSS security tools and
+ * other NSS test applications.
+ */
+
+ typedef struct {
+ enum {
+ PW_NONE = 0, /* no password */
+ PW_FROMFILE = 1, /* password stored in a file */
+ PW_PLAINTEXT = 2 /* plain-text password passed in buffer */
+ /* PW_EXTERNAL = 3 */
+ } source;
+ char *data;
+ /* depending on source this can be the actual
+ * password or the file to read it from
+ */
+ } secuPWData;
+
+ /*
+ * PrintAsAscii
+ */
+ extern void
+ PrintAsAscii(PRFileDesc* out, const unsigned char *data, unsigned int len);
+
+ /*
+ * PrintAsHex
+ */
+ extern void
+ PrintAsHex(PRFileDesc* out, const unsigned char *data, unsigned int len);
+
+ /*
+ * GetDigit
+ */
+ extern int
+ GetDigit(char c);
+
+ /*
+ * HexToBuf
+ */
+ extern int
+ HexToBuf(unsigned char *inString, SECItem *outbuf, PRBool isHexData);
+
+ /*
+ * FileToItem
+ */
+ extern SECStatus
+ FileToItem(SECItem *dst, PRFileDesc *src);
+
+ /*
+ * CheckPassword
+ */
+ extern PRBool
+ CheckPassword(char *cp);
+
+ /*
+ * GetPassword
+ */
+ extern char *
+ GetPassword(FILE *input,
+ FILE *output,
+ char *prompt,
+ PRBool (*ok)(char *));
+
+ /*
+ * FilePasswd extracts the password from a text file
+ *
+ * Storing passwords is often used with server environments
+ * where prompting the user for a password or requiring it
+ * to be entered in the commnd line is not a feasible option.
+ *
+ * This function supports password extraction from files with
+ * multipe passwords, one for each token. In the single password
+ * case a line would just have the passord whereas in the multi-
+ * password variant they could be of the form
+ *
+ * token_1_name:its_password
+ * token_2_name:its_password
+ *
+ */
+ extern char *
+ FilePasswd(PK11SlotInfo *
+ slot, PRBool retry, void *arg);
+
+ /*
+ * GetModulePassword
+ */
+ extern char *
+ GetModulePassword(PK11SlotInfo *slot,
+ int retry,
+ void *pwdata);
+
+ /*
+ * GenerateRandom
+ */
+ extern SECStatus
+ GenerateRandom(unsigned char *rbuf,
+ int rsize);
+
+ /*
+ * FileToItem
+ */
+ extern SECStatus
+ FileToItem(SECItem *dst,
+ PRFileDesc *src);
+
+ /*
+ * SeedFromNoiseFile
+ */
+ extern SECStatus
+ SeedFromNoiseFile(const char *noiseFileName);
+
+ /*
+ * FileSize
+ */
+ extern long
+ FileSize(const char* filename);
+
+ /*
+ * ReadDERFromFile
+ */
+ extern SECStatus
+ ReadDERFromFile(SECItem *der, const char *inFileName, PRBool ascii);
+
+ #endif /* _UTIL_H */
+
+`Util.c <#util.c>`__
+~~~~~~~~~~~~~~~~~~~~
+
+.. container::
+
+ .. 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/. */
+
+ #include "util.h"
+
+ /*
+ * These utility functions are adapted from those found in
+ * the sectool library used by the NSS security tools and
+ * other NSS test applications.
+ */
+
+ /*
+ * Newline
+ */
+ static void
+ Newline(PRFileDesc* out)
+ {
+ PR_fprintf(out, "\n");
+ }
+
+ /*
+ * PrintAsAscii
+ */
+ void
+ PrintAsAscii(PRFileDesc* out, const unsigned char *data, unsigned int len)
+ {
+ char *b64Data = NULL;
+
+ b64Data = BTOA_DataToAscii(data, len);
+ PR_fprintf(out, "%s", b64Data);
+ PR_fprintf(out, "\n");
+ if (b64Data) {
+ PORT_Free(b64Data);
+ }
+ }
+
+ /*
+ * PrintAsHex
+ */
+ void
+ PrintAsHex(PRFileDesc* out, const unsigned char *data, unsigned int len)
+ {
+ unsigned i;
+ int column;
+ unsigned int limit = 15;
+ unsigned int level = 1;
+
+ column = level;
+ if (!len) {
+ PR_fprintf(out, "(empty)\n");
+ return;
+ }
+
+ for (i = 0; i < len; i++) {
+ if (i != len - 1) {
+ PR_fprintf(out, "%02x:", data[i]);
+ column += 3;
+ } else {
+ PR_fprintf(out, "%02x", data[i]);
+ column += 2;
+ break;
+ }
+ if (column > 76 || (i % 16 == limit)) {
+ Newline(out);
+ column = level;
+ limit = i % 16;
+ }
+ }
+ if (column != level) {
+ Newline(out);
+ }
+ }
+
+ /*
+ * GetDigit
+ */
+ int
+ GetDigit(char c)
+ {
+ if (c == 0) {
+ return -1;
+ }
+ if (c <= '9' && c >= '0') {
+ return c - '0';
+ }
+ if (c <= 'f' && c >= 'a') {
+ return c - 'a' + 0xa;
+ }
+ if (c <= 'F' && c >= 'A') {
+ return c - 'A' + 0xa;
+ }
+ return -1;
+ }
+
+ /*
+ * HexToBuf
+ */
+ int
+ HexToBuf(unsigned char *inString, SECItem *outbuf, PRBool isHexData)
+ {
+ int len = strlen((const char *)inString);
+ int outLen = len+1/2;
+ int trueLen = 0;
+ int digit1, digit2;
+
+ outbuf->data = isHexData
+ ? PORT_Alloc(outLen)
+ : PORT_Alloc(len);
+ if (!outbuf->data) {
+ return -1;
+ }
+ if (isHexData) {
+ while (*inString) {
+ if ((*inString == '\n') || (*inString == ':')) {
+ inString++;
+ continue;
+ }
+ digit1 = GetDigit(*inString++);
+ digit2 = GetDigit(*inString++);
+ if ((digit1 == -1) || (digit2 == -1)) {
+ PORT_Free(outbuf->data);
+ outbuf->data = NULL;
+ return -1;
+ }
+ outbuf->data[trueLen++] = digit1 << 4 | digit2;
+ }
+ } else {
+ while (*inString) {
+ if (*inString == '\n') {
+ inString++;
+ continue;
+ }
+ outbuf->data[trueLen++] = *inString++;
+ }
+ outbuf->data[trueLen] = '\0';
+ trueLen = trueLen-1;
+ }
+ outbuf->len = trueLen;
+ return 0;
+ }
+
+ /*
+ * FileToItem
+ */
+ SECStatus
+ FileToItem(SECItem *dst, PRFileDesc *src)
+ {
+ PRFileInfo info;
+ PRInt32 numBytes;
+ PRStatus prStatus;
+
+ prStatus = PR_GetOpenFileInfo(src, &info);
+
+ if (prStatus != PR_SUCCESS) {
+ return SECFailure;
+ }
+
+ dst->data = 0;
+ if (SECITEM_AllocItem(NULL, dst, info.size)) {
+ numBytes = PR_Read(src, dst->data, info.size);
+ if (numBytes == info.size) {
+ return SECSuccess;
+ }
+ }
+ SECITEM_FreeItem(dst, PR_FALSE);
+ dst->data = NULL;
+ return SECFailure;
+ }
+
+ /*
+ * echoOff
+ */
+ static void echoOff(int fd)
+ {
+ if (isatty(fd)) {
+ struct termios tio;
+ tcgetattr(fd, &tio);
+ tio.c_lflag &= ~ECHO;
+ tcsetattr(fd, TCSAFLUSH, &tio);
+ }
+ }
+
+ /*
+ * echoOn
+ */
+ static void echoOn(int fd)
+ {
+ if (isatty(fd)) {
+ struct termios tio;
+ tcgetattr(fd, &tio);
+ tio.c_lflag |= ECHO;
+ tcsetattr(fd, TCSAFLUSH, &tio);
+ }
+ }
+
+ /*
+ * CheckPassword
+ */
+ PRBool CheckPassword(char *cp)
+ {
+ int len;
+ char *end;
+ len = PORT_Strlen(cp);
+ if (len < 8) {
+ return PR_FALSE;
+ }
+ end = cp + len;
+ while (cp < end) {
+ unsigned char ch = *cp++;
+ if (!((ch >= 'A') && (ch <= 'Z')) &&
+ !((ch >= 'a') && (ch <= 'z'))) {
+ return PR_TRUE;
+ }
+ }
+ return PR_FALSE;
+ }
+
+ /*
+ * GetPassword
+ */
+ char* GetPassword(FILE *input, FILE *output, char *prompt,
+ PRBool (*ok)(char *))
+ {
+ char phrase[200] = {'\0'};
+ int infd = fileno(input);
+ int isTTY = isatty(infd);
+
+ for (;;) {
+ /* Prompt for password */
+ if (isTTY) {
+ fprintf(output, "%s", prompt);
+ fflush (output);
+ echoOff(infd);
+ }
+ fgets(phrase, sizeof(phrase), input);
+ if (isTTY) {
+ fprintf(output, "\n");
+ echoOn(infd);
+ }
+ /* stomp on newline */
+ phrase[PORT_Strlen(phrase)-1] = 0;
+ /* Validate password */
+ if (!(*ok)(phrase)) {
+ if (!isTTY) return 0;
+ fprintf(output, "Password must be at least 8 characters long with one or more\n");
+ fprintf(output, "non-alphabetic characters\n");
+ continue;
+ }
+ return (char*) PORT_Strdup(phrase);
+ }
+ }
+
+ /*
+ * FilePasswd extracts the password from a text file
+ *
+ * Storing passwords is often used with server environments
+ * where prompting the user for a password or requiring it
+ * to be entered in the commnd line is not a feasible option.
+ *
+ * This function supports password extraction from files with
+ * multipe passwords, one for each token. In the single password
+ * case a line would just have the passord whereas in the multi-
+ * password variant they could be of the form
+ *
+ * token_1_name:its_password
+ * token_2_name:its_password
+ *
+ */
+ char *
+ FilePasswd(PK11SlotInfo *slot, PRBool retry, void *arg)
+ {
+ char* phrases, *phrase;
+ PRFileDesc *fd;
+ PRInt32 nb;
+ char *pwFile = arg;
+ int i;
+ const long maxPwdFileSize = 4096;
+ char* tokenName = NULL;
+ int tokenLen = 0;
+
+ if (!pwFile)
+ return 0;
+
+ if (retry) {
+ return 0; /* no good retrying - the files contents will be the same */
+ }
+
+ phrases = PORT_ZAlloc(maxPwdFileSize);
+
+ if (!phrases) {
+ return 0; /* out of memory */
+ }
+
+ fd = PR_Open(pwFile, PR_RDONLY, 0);
+ if (!fd) {
+ fprintf(stderr, "No password file \"%s\" exists.\n", pwFile);
+ PORT_Free(phrases);
+ return NULL;
+ }
+
+ nb = PR_Read(fd, phrases, maxPwdFileSize);
+
+ PR_Close(fd);
+
+ if (nb == 0) {
+ fprintf(stderr,"password file contains no data\n");
+ PORT_Free(phrases);
+ return NULL;
+ }
+
+ if (slot) {
+ tokenName = PK11_GetTokenName(slot);
+ if (tokenName) {
+ tokenLen = PORT_Strlen(tokenName);
+ }
+ }
+ i = 0;
+ do {
+ int startphrase = i;
+ int phraseLen;
+
+ /* handle the Windows EOL case */
+ while (phrases[i] != '\r' && phrases[i] != '\n' && i < nb) i++;
+
+ /* terminate passphrase */
+ phrases[i++] = '\0';
+ /* clean up any EOL before the start of the next passphrase */
+ while ( (i<nb) && (phrases[i] == '\r' || phrases[i] == '\n')) {
+ phrases[i++] = '\0';
+ }
+ /* now analyze the current passphrase */
+ phrase = &phrases[startphrase];
+ if (!tokenName)
+ break;
+ if (PORT_Strncmp(phrase, tokenName, tokenLen)) continue;
+ phraseLen = PORT_Strlen(phrase);
+ if (phraseLen < (tokenLen+1)) continue;
+ if (phrase[tokenLen] != ':') continue;
+ phrase = &phrase[tokenLen+1];
+ break;
+
+ } while (i<nb);
+
+ phrase = PORT_Strdup((char*)phrase);
+ PORT_Free(phrases);
+ return phrase;
+ }
+
+ /*
+ * GetModulePassword
+ */
+ char* GetModulePassword(PK11SlotInfo *slot, int retry, void *arg)
+ {
+ char prompt[255];
+ secuPWData *pwdata = (secuPWData *)arg;
+ char *pw;
+
+ if (pwdata == NULL) {
+ return NULL;
+ }
+
+ if (retry && pwdata->source != PW_NONE) {
+ PR_fprintf(PR_STDERR, "Incorrect password/PIN entered.\n");
+ return NULL;
+ }
+
+ switch (pwdata->source) {
+ case PW_NONE:
+ sprintf(prompt, "Enter Password or Pin for \"%s\":",
+ PK11_GetTokenName(slot));
+ return GetPassword(stdin, stdout, prompt, CheckPassword);
+ case PW_FROMFILE:
+ pw = FilePasswd(slot, retry, pwdata->data);
+ pwdata->source = PW_PLAINTEXT;
+ pwdata->data = PL_strdup(pw);
+ return pw;
+ case PW_PLAINTEXT:
+ return PL_strdup(pwdata->data);
+ default:
+ break;
+ }
+ PR_fprintf(PR_STDERR, "Password check failed: No password found.\n");
+ return NULL;
+ }
+
+ /*
+ * GenerateRandom
+ */
+ SECStatus
+ GenerateRandom(unsigned char *rbuf, int rsize)
+ {
+ char meter[] = {
+ "\r| |" };
+ int fd, count;
+ int c;
+ SECStatus rv = SECSuccess;
+ cc_t orig_cc_min;
+ cc_t orig_cc_time;
+ tcflag_t orig_lflag;
+ struct termios tio;
+
+ fprintf(stderr, "To generate random numbers, "
+ "continue typing until the progress meter is full:\n\n");
+ fprintf(stderr, "%s", meter);
+ fprintf(stderr, "\r|");
+
+ /* turn off echo on stdin & return on 1 char instead of NL */
+ fd = fileno(stdin);
+
+ tcgetattr(fd, &tio);
+ orig_lflag = tio.c_lflag;
+ orig_cc_min = tio.c_cc[VMIN];
+ orig_cc_time = tio.c_cc[VTIME];
+ tio.c_lflag &= ~ECHO;
+ tio.c_lflag &= ~ICANON;
+ tio.c_cc[VMIN] = 1;
+ tio.c_cc[VTIME] = 0;
+ tcsetattr(fd, TCSAFLUSH, &tio);
+ /* Get random noise from keyboard strokes */
+ count = 0;
+ while (count < rsize) {
+ c = getc(stdin);
+ if (c == EOF) {
+ rv = SECFailure;
+ break;
+ }
+ *(rbuf + count) = c;
+ if (count == 0 || c != *(rbuf + count -1)) {
+ count++;
+ fprintf(stderr, "*");
+ }
+ }
+ rbuf[count] = '\0';
+
+ fprintf(stderr, "\n\nFinished. Press enter to continue: ");
+ while ((c = getc(stdin)) != '\n' && c != EOF)
+ ;
+ if (c == EOF)
+ rv = SECFailure;
+ fprintf(stderr, "\n");
+
+ /* set back termio the way it was */
+ tio.c_lflag = orig_lflag;
+ tio.c_cc[VMIN] = orig_cc_min;
+ tio.c_cc[VTIME] = orig_cc_time;
+ tcsetattr(fd, TCSAFLUSH, &tio);
+ return rv;
+ }
+
+ /*
+ * SeedFromNoiseFile
+ */
+ SECStatus
+ SeedFromNoiseFile(const char *noiseFileName)
+ {
+ char buf[2048];
+ PRFileDesc *fd;
+ PRInt32 count;
+
+ fd = PR_Open(noiseFileName, PR_RDONLY, 0);
+ if (!fd) {
+ fprintf(stderr, "failed to open noise file.");
+ return SECFailure;
+ }
+
+ do {
+ count = PR_Read(fd,buf,sizeof(buf));
+ if (count > 0) {
+ PK11_RandomUpdate(buf,count);
+ }
+ } while (count > 0);
+
+ PR_Close(fd);
+ return SECSuccess;
+ }
+
+ /*
+ * FileSize
+ */
+ long FileSize(const char* filename)
+ {
+ struct stat stbuf;
+ stat(filename, &stbuf);
+ return stbuf.st_size;
+ }
+
+ /*
+ * ReadDERFromFile
+ */
+ SECStatus
+ ReadDERFromFile(SECItem *der, const char *inFileName, PRBool ascii)
+ {
+ SECStatus rv = SECSuccess;
+ PRFileDesc *inFile = NULL;
+
+ inFile = PR_Open(inFileName, PR_RDONLY, 0);
+ if (!inFile) {
+ PR_fprintf(PR_STDERR, "Failed to open file \"%s\" (%ld, %ld).\n",
+ inFileName, PR_GetError(), PR_GetOSError());
+ rv = SECFailure;
+ goto cleanup;
+ }
+
+ if (ascii) {
+ /* First convert ascii to binary */
+ SECItem filedata;
+ char *asc, *body;
+
+ /* Read in ascii data */
+ rv = FileToItem(&filedata, inFile);
+ asc = (char *)filedata.data;
+ if (!asc) {
+ 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(asc, "-----BEGIN")) != NULL) {
+ char *trailer = NULL;
+ asc = body;
+ body = PORT_Strchr(body, '\n');
+ if (!body)
+ body = PORT_Strchr(asc, '\r'); /* maybe this is a MAC file */
+ if (body)
+ trailer = strstr(++body, "-----END");
+ if (trailer != NULL) {
+ *trailer = '\0';
+ } else {
+ PR_fprintf(PR_STDERR, "input has header but no trailer\n");
+ PORT_Free(filedata.data);
+ rv = SECFailure;
+ goto cleanup;
+ }
+ } else {
+ body = asc;
+ }
+
+ /* Convert to binary */
+ rv = ATOB_ConvertAsciiToItem(der, body);
+ if (rv) {
+ PR_fprintf(PR_STDERR, "error converting ascii to binary %s\n",
+ PORT_GetError());
+ PORT_Free(filedata.data);
+ rv = SECFailure;
+ goto cleanup;
+ }
+
+ PORT_Free(filedata.data);
+ } else {
+ /* Read in binary der */
+ rv = FileToItem(der, inFile);
+ if (rv) {
+ PR_fprintf(PR_STDERR, "error converting der \n");
+ rv = SECFailure;
+ }
+ }
+ cleanup:
+ if (inFile) {
+ PR_Close(inFile);
+ }
+ return rv;
+ } \ No newline at end of file