PKI crypto operations


Sample 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 <string.h>

#include <nss.h>
#include <pk11pub.h>
#include <cert.h>
#include <keyhi.h>

#include <prtypes.h>
#include <nspr.h>
#include <prprf.h>
#include <prlog.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;
  PRBool             nssInitialized = PR_FALSE;
  CERTCertificate   *cert = NULL;
  SECKEYPublicKey   *pubKey = NULL;
  SECKEYPrivateKey  *pvtkey = NULL;
  unsigned int       modulusLen, outLen;
  unsigned char     *buf1 = NULL;
  unsigned char     *buf2 = NULL;
  unsigned char     *buf3 = NULL;
  int                i;

  do {
    /* Initialize NSS */
    PK11_SetPasswordFunc(passwdcb);
    rv = NSS_Init(".");
    if (rv != SECSuccess) {
      PR_fprintf(PR_STDERR, "NSS initialization failed (err %d)\n",
                 PR_GetError());
      break;
    }

    nssInitialized = PR_TRUE;

    cert = PK11_FindCertFromNickname("TestCA", NULL);
    if (!cert) {
      PR_fprintf(PR_STDERR, "Couldn't find cert TestCA in NSS db (err %d)\n",
                 PR_GetError());
      break;
    }

    pubKey = CERT_ExtractPublicKey(cert);
    if (!pubKey) {
      PR_fprintf(PR_STDERR,
                 "Couldn't extract public key from cert TestCA (err %d)\n",
                 PR_GetError());
      break;
    }

    modulusLen = SECKEY_PublicKeyStrength(pubKey);
    PR_fprintf(PR_STDOUT, "Public Key Modulus %d bytes\n", modulusLen);
    buf1 = PR_Malloc(modulusLen);
    buf2 = PR_Malloc(modulusLen);
    buf3 = PR_Malloc(modulusLen);

    /* initialize buf1 */
    for (i = 0; i < modulusLen; i++) {
      buf1[i]= (i % 26) + 'A';
    }
    buf1[modulusLen-1] = '\0';
    PR_fprintf(PR_STDOUT, "Buffer being encrypted = \n%s\n", buf1);

    /* encrypt buf1, result will be in buf2 */
    rv = PK11_PubEncryptRaw(pubKey, buf2, buf1, modulusLen, NULL);
    if (rv != SECSuccess) {
      PR_fprintf(PR_STDERR, "Encrypt with Public Key failed (err %d)\n",
                 PR_GetError());
      break;
    }

    pvtkey = PK11_FindKeyByAnyCert(cert, NULL);
    if (!pvtkey) {
      rv = PR_GetError();
      PR_fprintf(PR_STDERR,
                 "Couldn't find private key for cert TestCA (err %d)\n", rv);
      break;
    }

    /* decrypt buf2, result will be in buf3 */
    rv = PK11_PubDecryptRaw(pvtkey,
       		                buf3, &outLen, modulusLen,
                            buf3, modulusLen);
    if (rv != SECSuccess) {
      PR_fprintf(PR_STDERR, "Decrypt with Private Key failed (err %d)\n",
                 PR_GetError());
      break;
    }

    /* the recovered data better match the original */
    PR_ASSERT(memcmp(buf1, buf3, outLen) == 0);

    PR_fprintf(PR_STDOUT, "Result of decryption, outLen = %d\n", outLen);
    PR_fprintf(PR_STDOUT, "Result of decryption, buf = \n%s\n", buf3);

    rv = SECSuccess;

  } while (0);

/*cleanup:*/

  /* Pretend this is sensitive data and clear
   * our buffers before releasing them
   */
  if (buf1) { (void) memset(buf1, 0, modulusLen); PR_Free(buf1); }
  if (buf2) { (void) memset(buf2, 0, modulusLen); PR_Free(buf2); }
  if (buf3) { (void) memset(buf3, 0, modulusLen); PR_Free(buf2); }

  /*
   * Have NSS free what it allocated for us.
   */
  if (cert) CERT_DestroyCertificate(cert);
  if (pubKey) SECKEY_DestroyPublicKey(pubKey);
  if (pvtkey) SECKEY_DestroyPrivateKey(pvtkey);

  /* The last thing we do is shutdown nss */
  if (nssInitialized) {
  	(void) NSS_Shutdown(); /* ignoring the result code */
  }

  return rv;
}

/* Returns the password the firstime its called or NULL otherwise, no retry */
char *passwdcb(PK11SlotInfo *info, PRBool retry, void *arg)
{
  return (retry) ? NULL : PL_strdup("test");
}