Skip to content

Commit

Permalink
Merge pull request #7 from SLaks/master
Browse files Browse the repository at this point in the history
Add Windows Support
  • Loading branch information
danfuzz committed Dec 20, 2012
2 parents c1d6ff9 + 1aac8e0 commit 90a3af3
Show file tree
Hide file tree
Showing 10 changed files with 268 additions and 31 deletions.
21 changes: 19 additions & 2 deletions README.md
Original file line number Diff line number Diff line change
Expand Up @@ -9,6 +9,8 @@ on both Linux and OS X (the latter in several configurations, including
Node built from source as well as installed via MacPorts and Homebrew).
If you find it doesn't work for you, please file a bug (see below).

It has been tested on Windows by [SLaks](https://github.com/SLaks). (see additional installation requirements)


Building and Installing
-----------------------
Expand All @@ -20,7 +22,7 @@ npm install ursa
Or grab the source and

```shell
node-waf configure build
npm install
```

Testing
Expand All @@ -36,6 +38,22 @@ Or
node ./test/test.js
```

On Windows, you'll need to install some dependencies first:
- [node-gyp](https://github.com/TooTallNate/node-gyp/) (`npm install -g node-gyp`)
- [Python 2.7](http://www.python.org/download/releases/2.7.3#download) (not 3.3)
- Vistual Studio 2010 or higher (including Express editions)
- Windows XP/Vista/7:
- Microsoft Visual Studio C++ 2010 ([Express](http://go.microsoft.com/?linkid=9709949) version works well)
- For 64-bit builds of node and native modules you will _**also**_ need the [Windows 7 64-bit SDK](http://www.microsoft.com/en-us/download/details.aspx?id=8279)
- If you get errors that the 64-bit compilers are not installed you may also need the [compiler update for the Windows SDK 7.1](http://www.microsoft.com/en-us/download/details.aspx?id=4422)
- Windows 8:
- Microsoft Visual Studio C++ 2012 for Windows Desktop ([Express](http://go.microsoft.com/?linkid=9816758) version works well)
- [OpenSSL](http://slproweb.com/products/Win32OpenSSL.html) (normal, not light)
in the same bitness as your Node.js installation.
- The build script looks for OpenSSL in the default install directory
(`C:\OpenSSL-Win32` or `C:\OpenSSL-Win64`)
- If you get `Error: The specified module could not be found.`, copy `libeay32.dll` from the OpenSSL bin directory to this module's bin directory, or to Windows\System3.

Usage
-----

Expand Down Expand Up @@ -467,4 +485,3 @@ Copyright 2012 [The Obvious Corporation](http://obvious.com/).
Licensed under the Apache License, Version 2.0.
See the top-level file `LICENSE.txt` and
(http://www.apache.org/licenses/LICENSE-2.0).

60 changes: 42 additions & 18 deletions binding.gyp
Original file line number Diff line number Diff line change
@@ -1,20 +1,44 @@
{
'variables': {
# Default for this variable, to get the right behavior for
# Node versions <= 0.6.*.
'node_shared_openssl%': 'true'
},
'targets': [
{
'target_name': 'ursaNative',
'sources': [ 'src/ursaNative.cc' ],
'conditions': [
[ 'node_shared_openssl=="false"', {
'include_dirs': [
'<(node_root_dir)/deps/openssl/openssl/include'
]
}]
]
}
]
'variables': {
# Default for this variable, to get the right behavior for
# Node versions <= 0.6.*.
'node_shared_openssl%': 'true'
},
'targets': [
{
'target_name': 'ursaNative',
'sources': [ 'src/ursaNative.cc', 'src/asprintf.cc' ],
'conditions': [
[ 'OS=="win"', {
'conditions': [
# "openssl_root" is the directory on Windows of the OpenSSL files
['target_arch=="x64"', {
'variables': {
'openssl_root%': 'C:/OpenSSL-Win64'
},
}, {
'variables': {
'openssl_root%': 'C:/OpenSSL-Win32'
},
}],
],
'libraries': [
'-l<(openssl_root)/lib/libeay32.lib',
],
'include_dirs': [
'<(openssl_root)/include',
],
}, { # OS!="win"
'conditions': [
[ 'node_shared_openssl=="false"', {
'include_dirs': [
'<(node_root_dir)/deps/openssl/openssl/include'
]
}]
]
}],

]
}
]
}
15 changes: 15 additions & 0 deletions install.js
Original file line number Diff line number Diff line change
@@ -0,0 +1,15 @@
var fs = require('fs');
var path = require('path');

if (!(fs.existsSync || path.existsSync)('bin'))
fs.mkdirSync('bin');

moveAll('build/Release/', 'bin/', '.node');

function moveAll(from, to, ext) {
fs.readdirSync(from)
.filter(function(name) { return path.extname(name) === ext; })
.forEach(function(name) {
fs.rename(path.join(from, name), path.join(to, name));
});
}
2 changes: 1 addition & 1 deletion lib/ursa.js
Original file line number Diff line number Diff line change
Expand Up @@ -44,7 +44,7 @@ var MD5 = "md5";

/** regex that matches PEM files, capturing the file type */
var PEM_REGEX =
/^(-----BEGIN (.*) KEY-----\n[\/+=a-zA-Z0-9\n]*\n-----END \2 KEY-----\n)/m;
/^(-----BEGIN (.*) KEY-----\r?\n[\/+=a-zA-Z0-9\r\n]*\r?\n-----END \2 KEY-----\r?\n)/m;

/** "unsealer" key object to authenticate objects */
var theUnsealer = [ "ursa unsealer" ];
Expand Down
2 changes: 1 addition & 1 deletion package.json
Original file line number Diff line number Diff line change
Expand Up @@ -33,7 +33,7 @@
},

"scripts": {
"install": "node-gyp configure build; mkdir -p bin; mv build/Release/*.node bin",
"install": "node-gyp configure build && node install.js",
"test": "node test/test.js"
}
}
107 changes: 107 additions & 0 deletions src/asprintf.cc
Original file line number Diff line number Diff line change
@@ -0,0 +1,107 @@

/*
* Copyright (c) 2004 Darren Tucker.
*
* Based originally on asprintf.c from OpenBSD:
* Copyright (c) 1997 Todd C. Miller <Todd.Miller AT courtesan.com>
*
* Permission to use, copy, modify, and distribute this software for any
* purpose with or without fee is hereby granted, provided that the above
* copyright notice and this permission notice appear in all copies.
*
* THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES
* WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF
* MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR
* ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES
* WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN
* ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF
* OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE.
*/

#include "asprintf.h"

/* Include vasprintf() if not on your OS. */
#ifndef HAVE_VASPRINTF
#define HAVE_VASPRINTF

#include <errno.h>
#include <limits.h>
#include <stdarg.h>
#include <stdlib.h>
#include <stdio.h>

#ifndef VA_COPY
# ifdef HAVE_VA_COPY
# define VA_COPY(dest, src) va_copy(dest, src)
# else
# ifdef HAVE___VA_COPY
# define VA_COPY(dest, src) __va_copy(dest, src)
# else
# define VA_COPY(dest, src) (dest) = (src)
# endif
# endif
#endif

#define INIT_SZ 128

int
vasprintf(char **str, const char *fmt, va_list ap)
{
int ret = -1;
va_list ap2;
char *string, *newstr;
size_t len;

VA_COPY(ap2, ap);
if ((string = (char*)malloc(INIT_SZ)) == NULL)
goto fail;

ret = vsnprintf(string, INIT_SZ, fmt, ap2);
if (ret >= 0 && ret < INIT_SZ) { /* succeeded with initial alloc */
*str = string;
} else if (ret == INT_MAX || ret < 0) { /* Bad length */
goto fail;
} else { /* bigger than initial, realloc allowing for nul */
len = (size_t)ret + 1;
if ((newstr = (char*)realloc(string, len)) == NULL) {
free(string);
goto fail;
} else {
va_end(ap2);
VA_COPY(ap2, ap);
ret = vsnprintf(newstr, len, fmt, ap2);
if (ret >= 0 && (size_t)ret < len) {
*str = newstr;
} else { /* failed with realloc'ed string, give up */
free(newstr);
goto fail;
}
}
}
va_end(ap2);
return (ret);

fail:
*str = NULL;
errno = ENOMEM;
va_end(ap2);
return (-1);
}
#endif

/* Include asprintf() if not on your OS. */
#ifndef HAVE_ASPRINTF
#define HAVE_ASPRINTF
int asprintf(char **str, const char *fmt, ...)
{
va_list ap;
int ret;

*str = NULL;
va_start(ap, fmt);
ret = vasprintf(str, fmt, ap);
va_end(ap);

return ret;
}
#endif
40 changes: 40 additions & 0 deletions src/asprintf.h
Original file line number Diff line number Diff line change
@@ -0,0 +1,40 @@

/*
* Copyright (c) 2004 Darren Tucker.
*
* Based originally on asprintf.c from OpenBSD:
* Copyright (c) 1997 Todd C. Miller <Todd.Miller AT courtesan.com>
*
* Permission to use, copy, modify, and distribute this software for any
* purpose with or without fee is hereby granted, provided that the above
* copyright notice and this permission notice appear in all copies.
*
* THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES
* WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF
* MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR
* ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES
* WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN
* ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF
* OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE.
*/


#ifndef ASPRINTF_H
#define ASPRINTF_H

#include <stdlib.h>

#ifndef _WIN32
# define HAVE_VASPRINTF
# define HAVE_ASPRINTF
#endif

#ifndef HAVE_VASPRINTF
int vasprintf(char **str, const char *fmt, va_list ap);
#endif

#ifndef HAVE_ASPRINTF
int asprintf(char **str, const char *fmt, ...);
#endif

#endif
26 changes: 24 additions & 2 deletions src/ursaNative.cc
Original file line number Diff line number Diff line change
Expand Up @@ -8,9 +8,18 @@
#include <openssl/ssl.h>
#include <openssl/err.h>
#include <openssl/pem.h>
#include "asprintf.h"

using namespace v8;

#ifdef _WIN32
# include <malloc.h>
# define VAR_ARRAY(type, name, size) type* name = (type*)_alloca(size)
#else
# define VAR_ARRAY(type, name, size) type name[size]
#endif



/*
* Initialization and binding
Expand All @@ -31,6 +40,19 @@ void init(Handle<Object> target) {
NODE_DEFINE_CONSTANT(target, RSA_PKCS1_OAEP_PADDING);
BIND(target, textToNid, TextToNid);
RsaWrap::InitClass(target);

#ifdef _WIN32
// On Windows, we can't use Node's OpenSSL, so we link
// to a standalone OpenSSL library. Therefore, we need
// to initialize OpenSSL separately.

//TODO: Do I need to free these?
//I'm not sure where to call ERR_free_strings() and EVP_cleanup()
OpenSSL_add_all_digests();
OpenSSL_add_all_algorithms();
OpenSSL_add_all_ciphers();
ERR_load_crypto_strings();
#endif
}

NODE_MODULE(ursaNative, init)
Expand Down Expand Up @@ -615,7 +637,7 @@ Handle<Value> RsaWrap::PrivateDecrypt(const Arguments& args) {
if (data == NULL) { return Undefined(); }

int rsaLength = RSA_size(obj->rsa);
unsigned char buf[rsaLength];
VAR_ARRAY(unsigned char, buf, rsaLength);

int padding;
if (!getArgInt(args, 1, &padding)) { return Undefined(); }
Expand Down Expand Up @@ -690,7 +712,7 @@ Handle<Value> RsaWrap::PublicDecrypt(const Arguments& args) {
if (data == NULL) { return Undefined(); }

int rsaLength = RSA_size(obj->rsa);
unsigned char buf[rsaLength];
VAR_ARRAY(unsigned char, buf, rsaLength);

int bufLength = RSA_public_decrypt(length, (unsigned char *) data,
buf, obj->rsa, RSA_PKCS1_PADDING);
Expand Down
12 changes: 9 additions & 3 deletions test/native.js
Original file line number Diff line number Diff line change
Expand Up @@ -17,6 +17,12 @@ var RsaWrap = fixture.RsaWrap;
var ursaNative = fixture.ursaNative;
var textToNid = ursaNative.textToNid;

/**
* Asserts that two strings are equal, ignoring Windows newline differences
*/
function assertStringEqual(actual, expected, message) {
assert.equal(actual.replace(/\r\n/g, '\n'), expected.replace(/\r\n/g, '\n'), message);
}

/*
* Test functions
Expand Down Expand Up @@ -156,7 +162,7 @@ function test_getPrivateKeyPem() {
rsa.setPrivateKeyPem(fixture.PRIVATE_KEY);

var pem = rsa.getPrivateKeyPem().toString(fixture.UTF8);
assert.equal(pem, keyStr);
assertStringEqual(pem, keyStr);
}

function test_fail_getPrivateKeyPem() {
Expand All @@ -177,12 +183,12 @@ function test_getPublicKeyPem() {
var rsa = new RsaWrap();
rsa.setPublicKeyPem(fixture.PUBLIC_KEY);
var pem = rsa.getPublicKeyPem().toString(fixture.UTF8);
assert.equal(pem, keyStr);
assertStringEqual(pem, keyStr);

rsa = new RsaWrap();
rsa.setPrivateKeyPem(fixture.PRIVATE_KEY);
pem = rsa.getPublicKeyPem().toString(fixture.UTF8);
assert.equal(pem, keyStr);
assertStringEqual(pem, keyStr);
}

function test_fail_getPublicKeyPem() {
Expand Down
Loading

0 comments on commit 90a3af3

Please sign in to comment.