Skip to content

Commit

Permalink
csp: add support import PFX (PKCS12)
Browse files Browse the repository at this point in the history
  • Loading branch information
algv committed May 23, 2018
1 parent d83624f commit 0452390
Show file tree
Hide file tree
Showing 6 changed files with 182 additions and 0 deletions.
1 change: 1 addition & 0 deletions deps/wrapper/include/wrapper/utils/csp.h
Original file line number Diff line number Diff line change
Expand Up @@ -53,6 +53,7 @@ class Csp {

bool isHaveExportablePrivateKey(Handle<Certificate> cert);
Handle<Pkcs12> certToPkcs12(Handle<Certificate> cert, bool exportPrivateKey, Handle<std::string> password);
void importPkcs12(Handle<Pkcs12> p12, Handle<std::string> password);

#ifdef CSP_ENABLE
PCCERT_CONTEXT static createCertificateContext(Handle<Certificate> cert);
Expand Down
133 changes: 133 additions & 0 deletions deps/wrapper/src/utils/csp.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -1651,6 +1651,139 @@ Handle<Pkcs12> Csp::certToPkcs12(Handle<Certificate> cert, bool exportPrivateKey
}
}

void Csp::importPkcs12(Handle<Pkcs12> p12, Handle<std::string> password) {
LOGGER_FN();

HCERTSTORE hCertStore = HCRYPT_NULL;
HCERTSTORE hImportCertStore = HCRYPT_NULL;
PCCERT_CONTEXT pCertContext = HCRYPT_NULL;

try {
CRYPT_DATA_BLOB bDataBlob = { 0, NULL };
WCHAR wPassword[MAX_PATH];
DWORD dwSize = 0;
unsigned char *pData = NULL, *p = NULL;
const unsigned char *pCert;
int iData;
X509 *xcert = NULL;
wchar_t *storeName = L"MY";

if (p12->isEmpty()) {
THROW_OPENSSL_EXCEPTION(0, Csp, NULL, "p12 cannot be empty");
}

if (!password.isEmpty()) {
if (mbstowcs(wPassword, password->c_str(), MAX_PATH) <= 0) {
THROW_EXCEPTION(0, Csp, NULL, "mbstowcs failed");
}
}

LOGGER_OPENSSL(i2d_PKCS12);
if ((iData = i2d_PKCS12(p12->internal(), NULL)) <= 0) {
THROW_OPENSSL_EXCEPTION(0, Csp, NULL, "Error i2d_PKCS12");
}

LOGGER_OPENSSL(OPENSSL_malloc);
if (NULL == (pData = (unsigned char*)OPENSSL_malloc(iData))) {
THROW_OPENSSL_EXCEPTION(0, Csp, NULL, "Error malloc");
}

p = pData;
LOGGER_OPENSSL(i2d_PKCS12);
if ((iData = i2d_PKCS12(p12->internal(), &p)) <= 0) {
THROW_OPENSSL_EXCEPTION(0, Csp, NULL, "Error i2d_PKCS12");
}

bDataBlob.cbData = iData;
bDataBlob.pbData = pData;

if (!(hImportCertStore = PFXImportCertStore(&bDataBlob, wPassword, CRYPT_USER_KEYSET | PKCS12_ALLOW_OVERWRITE_KEY))) {
THROW_EXCEPTION(0, Csp, NULL, "PFXImportCertStore failed. Code: %d", GetLastError());
}

while (pCertContext = CertEnumCertificatesInStore(hImportCertStore, pCertContext)) {
pCert = pCertContext->pbCertEncoded;

LOGGER_OPENSSL(d2i_X509);
if (!(xcert = d2i_X509(NULL, &pCert, pCertContext->cbCertEncoded))) {
THROW_OPENSSL_EXCEPTION(0, Csp, NULL, "'d2i_X509' Error decode len bytes");
}

Handle<Certificate> hcert = new Certificate(xcert);

if (CertGetCertificateContextProperty(pCertContext,
CERT_KEY_PROV_INFO_PROP_ID,
NULL,
&dwSize)
)
{
storeName = L"MY";
}
else if (hcert->isCA()) {
if (hcert->isSelfSigned()) {
storeName = L"ROOT";
}
else {
storeName = L"CA";
}
}
else {
storeName = L"AddressBook";
}

if (HCRYPT_NULL == (hCertStore = CertOpenStore(
CERT_STORE_PROV_SYSTEM,
X509_ASN_ENCODING | PKCS_7_ASN_ENCODING,
HCRYPT_NULL,
CERT_SYSTEM_STORE_CURRENT_USER,
storeName)))
{
THROW_EXCEPTION(0, Csp, NULL, "CertOpenStore failed: Code: %d", GetLastError());
}

if (!CertAddCertificateContextToStore(
hCertStore,
pCertContext,
CERT_STORE_ADD_REPLACE_EXISTING,
NULL
))
{
THROW_EXCEPTION(0, Csp, NULL, "CertAddCertificateContextToStore failed. Code: %d", GetLastError())
}

CertCloseStore(hCertStore, 0);
hCertStore = HCRYPT_NULL;
}

OPENSSL_free(pData);

CertFreeCertificateContext(pCertContext);
pCertContext = HCRYPT_NULL;

if (hImportCertStore) {
CertCloseStore(hImportCertStore, 0);
hImportCertStore = HCRYPT_NULL;
}
}
catch (Handle<Exception> e) {
if (pCertContext) {
CertFreeCertificateContext(pCertContext);
}

if (hImportCertStore) {
CertCloseStore(hImportCertStore, 0);
hImportCertStore = HCRYPT_NULL;
}

if (hCertStore) {
CertCloseStore(hCertStore, 0);
hCertStore = HCRYPT_NULL;
}

THROW_EXCEPTION(0, Csp, e, "Error import pfx");
}
}

CRYPT_KEY_PROV_INFO * Csp::getCertificateContextProperty(
IN PCCERT_CONTEXT pCertContext,
IN DWORD dwPropId) {
Expand Down
1 change: 1 addition & 0 deletions lib/native.ts
Original file line number Diff line number Diff line change
Expand Up @@ -554,6 +554,7 @@ declare namespace native {
public verifyCertificateChain(cert: PKI.Certificate): boolean;
public isHaveExportablePrivateKey(cert: PKI.Certificate): boolean;
public certToPkcs12(cert: PKI.Certificate, exportPrivateKey: boolean, password?: string): PKI.Pkcs12;
public importPkcs12(p12: PKI.Pkcs12, password?: string): void;
}
}

Expand Down
16 changes: 16 additions & 0 deletions lib/utils/csp.ts
Original file line number Diff line number Diff line change
Expand Up @@ -221,6 +221,22 @@ namespace trusted.utils {
(csp.certToPkcs12(cert.handle, exportPrivateKey, password));
}

/**
* Import PFX to store
*
* @static
* @param {pki.Pkcs12} p12
* @param {string} [password]
* @returns {void}
* @memberof Csp
*/
public static importPkcs12(p12: pki.Pkcs12, password?: string): void {
const csp = new native.UTILS.Csp();

csp.importPkcs12(p12.handle, password);
return;
}

/**
* Creates an instance of Csp.
*
Expand Down
30 changes: 30 additions & 0 deletions src/node/utils/wcsp.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -41,6 +41,7 @@ void WCsp::Init(v8::Handle<v8::Object> exports) {

Nan::SetPrototypeMethod(tpl, "isHaveExportablePrivateKey", IsHaveExportablePrivateKey);
Nan::SetPrototypeMethod(tpl, "certToPkcs12", CertToPkcs12);
Nan::SetPrototypeMethod(tpl, "importPkcs12", ImportPkcs12);

// Store the constructor in the target bindings.
constructor().Reset(Nan::GetFunction(tpl).ToLocalChecked());
Expand Down Expand Up @@ -531,3 +532,32 @@ NAN_METHOD(WCsp::CertToPkcs12) {
}
TRY_END();
}

NAN_METHOD(WCsp::ImportPkcs12) {
METHOD_BEGIN();

try {
#ifdef CSP_ENABLE
LOGGER_ARG("p12");
WPkcs12 * wP12 = WPkcs12::Unwrap<WPkcs12>(info[0]->ToObject());

Handle<std::string> hpass;

LOGGER_ARG("password");
if (!info[1]->IsUndefined()){
v8::String::Utf8Value v8Pass(info[1]->ToString());
hpass = new std::string(*v8Pass);
}

UNWRAP_DATA(Csp);

_this->importPkcs12(wP12->data_, hpass);

info.GetReturnValue().Set(info.This());
return;
#else
Nan::ThrowError("Only if CSP_ENABLE");
#endif // CSP_ENABLE
}
TRY_END();
}
1 change: 1 addition & 0 deletions src/node/utils/wcsp.h
Original file line number Diff line number Diff line change
Expand Up @@ -39,6 +39,7 @@ WRAP_CLASS(Csp){

static NAN_METHOD(IsHaveExportablePrivateKey);
static NAN_METHOD(CertToPkcs12);
static NAN_METHOD(ImportPkcs12);
};

#endif //!UTIL_WCSP_INCLUDED

0 comments on commit 0452390

Please sign in to comment.