Skip to content
Snippets Groups Projects
Commit 47f22a6b authored by deuce's avatar deuce
Browse files

Add new private_key object to CryptContext (not in JSDOCS). Values are in

the format required by ACMEv2/Let's Encrypt.

Yes, this seems to be the easiest way to exfiltrate a private key from
a cryptlib context.
parent 89e37d12
No related branches found
No related tags found
No related merge requests found
......@@ -6,6 +6,7 @@
#include <cryptlib.h>
#include "js_request.h"
#include "ssl.h"
#include "base64.h"
struct private_data {
CRYPT_CONTEXT ctx;
......@@ -39,6 +40,226 @@ js_cryptcon_error(JSContext *cx, CRYPT_CONTEXT ctx, int error)
free(errstr);
}
static size_t js_asn1_len(unsigned char *data, size_t len, size_t *off)
{
size_t sz = 0;
size_t bytes;
size_t i;
if (*off >= len)
return 0;
if ((data[*off] & 0x80) == 0) {
sz = data[*off];
(*off)++;
}
else if(data[*off] == 0x80) {
// We can't actually handle this when we're this simple.
(*off)++;
}
else {
bytes = data[(*off)++] & 0x7f;
for (i = 0; i < bytes && *off < len; i++) {
sz <<= 8;
sz |= data[(*off)++];
}
}
return sz;
}
static unsigned char js_asn1_type(unsigned char *data, size_t len, size_t *off)
{
unsigned char t = 0;
if ((data[*off] & 0x1f) == 0x1f) {
for ((*off)++; *off < len && data[*off]; (*off)++) {
if ((data[*off] & 0x80) == 0)
break;
}
}
else {
t = data[*off];
(*off)++;
}
return t;
}
static void js_simple_asn1(unsigned char *data, size_t len, JSContext *cx, JSObject *parent)
{
unsigned char t;
size_t off=0;
size_t sz;
char *e;
char *n;
char *e64;
char *n64;
JSObject *obj;
JSString* estr;
JSString* nstr;
while(off < len) {
/* Parse identifier */
t = js_asn1_type(data, len, &off);
/* Parse length */
sz = js_asn1_len(data, len, &off);
switch(t) {
case 48:
// Sequence, descend into it.
break;
case 6:
// OID.... check if it's PKCS #1
if (strncmp((char *)data+off, "\x2a\x86\x48\x86\xF7\x0D\x01\x01\x01", 9)==0) {
// YEP!
off += sz;
off += 9;
if (js_asn1_type(data, len, &off) == 2) {
sz = js_asn1_len(data,len,&off);
n = malloc(sz);
if (n == NULL)
return;
memcpy(n, data+off, sz);
n64 = malloc(sz*4/3+3);
if (n64 == NULL) {
free(n);
return;
}
b64_encode(n64, sz*4/3+3, n, sz);
free(n);
for (n=n64; *n; n++) {
if (*n == '+')
*n = '-';
else if (*n == '/')
*n = '_';
else if (*n == '=')
*n = 0;
}
off += sz;
if (js_asn1_type(data, len, &off) != 2) {
free(n64);
return;
}
sz = js_asn1_len(data,len,&off);
e = malloc(sz);
if (e == NULL) {
free(n64);
return;
}
memcpy(e, data+off, sz);
e64 = malloc(sz*4/3+3);
if (e64 == NULL) {
free(e);
free(n64);
return;
}
b64_encode(e64, sz*4/3+3, e, sz);
for (e=e64; *e; e++) {
if (*e == '+')
*e = '-';
else if (*e == '/')
*e = '_';
else if (*e == '=')
*e = 0;
}
free(e);
obj=JS_NewObject(cx, NULL, NULL, parent);
JS_DefineProperty(cx, parent, "public_key", OBJECT_TO_JSVAL(obj), NULL, NULL, JSPROP_ENUMERATE|JSPROP_READONLY);
nstr=JS_NewStringCopyZ(cx, n64);
if (nstr != NULL)
JS_DefineProperty(cx, obj, "n", STRING_TO_JSVAL(nstr), NULL, NULL, JSPROP_ENUMERATE|JSPROP_READONLY);
estr=JS_NewStringCopyZ(cx, e64);
if (estr != NULL)
JS_DefineProperty(cx, obj, "e", STRING_TO_JSVAL(estr), NULL, NULL, JSPROP_ENUMERATE|JSPROP_READONLY);
JS_DeepFreezeObject(cx, obj);
}
off = len;
}
off += sz;
break;
default:
off += sz;
break;
}
}
}
static void js_create_key_object(JSContext *cx, JSObject *parent)
{
struct private_data* p;
jsrefcount rc;
int status;
int val;
int sz;
CRYPT_CERTIFICATE cert; // Just to hold the public key...
unsigned char *certbuf;
if ((p=(struct private_data *)JS_GetPrivate(cx,parent))==NULL)
return;
rc = JS_SUSPENDREQUEST(cx);
status = cryptGetAttribute(p->ctx, CRYPT_CTXINFO_ALGO, &val);
if (status != CRYPT_OK) {
lprintf(LOG_ERR, "cryptGetAttribute(ALGO) returned %d\n", status);
goto resume;
}
if (val != CRYPT_ALGO_RSA)
goto resume;
status = cryptCreateCert(&cert, CRYPT_UNUSED, CRYPT_CERTTYPE_CERTIFICATE);
if (status != CRYPT_OK) {
lprintf(LOG_ERR, "cryptCreateCert() returned %d\n", status);
goto resume;
}
status = cryptSetAttribute(cert, CRYPT_CERTINFO_SUBJECTPUBLICKEYINFO, p->ctx);
if (status != CRYPT_OK) {
lprintf(LOG_ERR, "cryptSetAttribute(PKI) returned %d\n", status);
goto resume;
}
status = cryptSetAttribute(cert, CRYPT_CERTINFO_XYZZY, 1);
if (status != CRYPT_OK) {
lprintf(LOG_ERR, "cryptSetAttribute(XYZZY) returned %d\n", status);
goto resume;
}
status = cryptSetAttributeString(cert, CRYPT_CERTINFO_COMMONNAME, "Key", 3);
if (status != CRYPT_OK) {
lprintf(LOG_ERR, "cryptSetAttributeString(CN) returned %d\n", status);
goto resume;
}
status = cryptSignCert(cert, p->ctx);
if (status != CRYPT_OK) {
lprintf(LOG_ERR, "cryptSignCert() returned %d\n", status);
goto resume;
}
status = cryptExportCert(NULL, 0, &sz, CRYPT_CERTFORMAT_CERTIFICATE, cert);
if (status != CRYPT_OK) {
lprintf(LOG_ERR, "cryptExportCert(NULL) returned %d\n", status);
goto resume;
}
certbuf = malloc(sz);
if (certbuf == NULL) {
lprintf(LOG_ERR, "Unable to allocate %d bytes\n", sz);
goto resume;
}
status = cryptExportCert(certbuf, sz, &sz, CRYPT_CERTFORMAT_CERTIFICATE, cert);
if (status != CRYPT_OK) {
lprintf(LOG_ERR, "cryptExportCert(certbuf) returned %d\n", status);
goto resume;
}
cryptDestroyCert(cert);
js_simple_asn1(certbuf, sz, cx, parent);
free(certbuf);
resume:
JS_RESUMEREQUEST(cx, rc);
return;
}
// Destructor
static void
......@@ -64,6 +285,7 @@ js_generate_key(JSContext *cx, uintN argc, jsval *arglist)
JSObject *obj=JS_THIS_OBJECT(cx, arglist);
jsrefcount rc;
int status;
char kname[32];
if ((p=(struct private_data *)JS_GetPrivate(cx,obj))==NULL) {
JS_ReportError(cx, getprivate_failure, WHERE);
......@@ -71,8 +293,13 @@ js_generate_key(JSContext *cx, uintN argc, jsval *arglist)
}
rc = JS_SUSPENDREQUEST(cx);
status = cryptGenerateKey(p->ctx);
sprintf(kname, "Key-%d", p->ctx);
status = cryptSetAttributeString(p->ctx, CRYPT_CTXINFO_LABEL, kname, strlen(kname));
if (status == CRYPT_OK)
status = cryptGenerateKey(p->ctx);
JS_RESUMEREQUEST(cx, rc);
if (status == CRYPT_OK)
js_create_key_object(cx, obj);
if (cryptStatusError(status)) {
js_cryptcon_error(cx, p->ctx, status);
return JS_FALSE;
......@@ -117,6 +344,7 @@ js_set_key(JSContext *cx, uintN argc, jsval *arglist)
js_cryptcon_error(cx, p->ctx, status);
return JS_FALSE;
}
js_create_key_object(cx, obj);
JS_SET_RVAL(cx, arglist, JSVAL_VOID);
return JS_TRUE;
......@@ -164,6 +392,7 @@ js_derive_key(JSContext *cx, uintN argc, jsval *arglist)
js_cryptcon_error(cx, p->ctx, status);
return JS_FALSE;
}
js_create_key_object(cx, obj);
JS_SET_RVAL(cx, arglist, JSVAL_VOID);
return JS_TRUE;
......
0% Loading or .
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment