|
// 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;
|
|
}
|