Project

General

Profile

Bug #11128 ยป nss_test.cc

Zheng Yan, 03/20/2015 01:16 PM

 
// g++ nss_test.cc -l rados -I/usr/include/nspr4/ -I/usr/include/nss3/ -lnss3 -lnspr4
//
#include <sys/types.h>
#include <sys/wait.h>
#include <unistd.h>
#include <assert.h>
#include <nspr.h>
#include <nss.h>
#include <pk11pub.h>
#include <sstream>
#include <iostream>
#include <rados/librados.hpp>

#define CEPH_AES_IV "cephsageyudagreg"

static void nss_aes_operation(CK_ATTRIBUTE_TYPE op,
const ceph::bufferptr& secret,
const librados::bufferlist& in,
librados::bufferlist& out,
std::string &error)
{
const CK_MECHANISM_TYPE mechanism = CKM_AES_CBC_PAD;

// sample source said this has to be at least size of input + 8,
// but i see 15 still fail with SEC_ERROR_OUTPUT_LEN
ceph::bufferptr out_tmp(in.length()+16);

PK11SlotInfo *slot;

slot = PK11_GetBestSlot(mechanism, NULL);
if (!slot) {
std::ostringstream oss;
oss << "cannot find NSS slot to use: " << PR_GetError();
error = oss.str();
goto err;
}

SECItem keyItem;

keyItem.type = siBuffer;
keyItem.data = (unsigned char*)secret.c_str();
keyItem.len = secret.length();

PK11SymKey *key;

key = PK11_ImportSymKey(slot, mechanism, PK11_OriginUnwrap, CKA_ENCRYPT,
&keyItem, NULL);
if (!key) {
std::ostringstream oss;
oss << "cannot convert AES key for NSS: " << PR_GetError();
error = oss.str();
goto err_slot;
}

SECItem ivItem;

ivItem.type = siBuffer;
// losing constness due to SECItem.data; IV should never be
// modified, regardless
ivItem.data = (unsigned char*)CEPH_AES_IV;
ivItem.len = sizeof(CEPH_AES_IV);

SECItem *param;

param = PK11_ParamFromIV(mechanism, &ivItem);
if (!param) {
std::ostringstream oss;
oss << "cannot set NSS IV param: " << PR_GetError();
error = oss.str();
goto err_key;
}

PK11Context *ctx;

ctx = PK11_CreateContextBySymKey(mechanism, op, key, param);
if (!ctx) {
std::ostringstream oss;
oss << "cannot create NSS context: " << PR_GetError();
error = oss.str();
goto err_param;
}

SECStatus ret;
int written;
// in is const, and PK11_CipherOp is not; C++ makes this hard to cheat,
// so just copy it to a temp buffer, at least for now
unsigned in_len;
unsigned char *in_buf;
in_len = in.length();
in_buf = (unsigned char*)malloc(in_len);
if (!in_buf)
throw std::bad_alloc();
in.copy(0, in_len, (char*)in_buf);
ret = PK11_CipherOp(ctx, (unsigned char*)out_tmp.c_str(), &written, out_tmp.length(),
in_buf, in.length());
free(in_buf);
if (ret != SECSuccess) {
std::ostringstream oss;
oss << "NSS AES failed: " << PR_GetError();
error = oss.str();
goto err_op;
}

unsigned int written2;
ret = PK11_DigestFinal(ctx, (unsigned char*)out_tmp.c_str()+written, &written2,
out_tmp.length()-written);
if (ret != SECSuccess) {
std::ostringstream oss;
oss << "NSS AES final round failed: " << PR_GetError();
error = oss.str();
goto err_op;
}

out_tmp.set_length(written + written2);
out.append(out_tmp);

PK11_DestroyContext(ctx, PR_TRUE);
SECITEM_FreeItem(param, PR_TRUE);
PK11_FreeSymKey(key);
PK11_FreeSlot(slot);
return;

err_op:
PK11_DestroyContext(ctx, PR_TRUE);
err_param:
SECITEM_FreeItem(param, PR_TRUE);
err_key:
PK11_FreeSymKey(key);
err_slot:
PK11_FreeSlot(slot);
err:
;
}

void nss_test(void) {
std::string secret_str = "AQCUswtVs16kHhAAE3EY2eLllJbpGJTD";
ceph::bufferptr secret(secret_str.c_str(), secret_str.length());

librados::bufferlist in;
in.append("hello world");
librados::bufferlist out;

std::string error;
nss_aes_operation(CKA_ENCRYPT, secret, in, out, error);
if (!error.empty())
std::cout << "nss_aes_operation " << error << std::endl;
}

void nss_init(void) {
SECStatus s;
s = NSS_NoDB_Init(NULL);
assert(s == SECSuccess);
}

int main(int argc, const char **argv)
{
nss_init();

pid_t pid = fork();
if (pid == 0) {
nss_test();
} else {
nss_test();
int status;
assert(pid == waitpid(pid, &status, 0));
assert(status == 0);
}
return 0;
}
    (1-1/1)