openssl_pkcs8 0.1.0 → 0.1.1
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- data/README.rdoc +13 -3
- data/VERSION +1 -0
- data/ext/openssl_pkcs8/openssl_pkcs8.c +191 -0
- data/ext/openssl_pkcs8/openssl_pkcs8.o +0 -0
- data/lib/openssl_pkcs8.rb +3 -0
- data/openssl-pkcs8.o +0 -0
- data/openssl_pkcs8.gemspec +54 -0
- data/test/test_openssl_pkcs8.rb +24 -0
- metadata +11 -4
data/README.rdoc
CHANGED
@@ -5,10 +5,20 @@ is part of standard Ruby distributions.
|
|
5
5
|
|
6
6
|
Example:
|
7
7
|
|
8
|
-
|
8
|
+
key = OpenSSL::PKey::RSA.new(1024)
|
9
|
+
|
10
|
+
key.to_pem_pkcs8
|
11
|
+
# => "-----BEGIN PRIVATE KEY----- ..."
|
12
|
+
|
13
|
+
This will export the private key in PKCS8 format, and will export public keys
|
14
|
+
in the PUBKEY format used by OpenSSL. Note the absence of "RSA" in both of
|
15
|
+
the headers.
|
9
16
|
|
10
|
-
|
11
|
-
|
17
|
+
== Installation
|
18
|
+
|
19
|
+
Using the Gem distribution is probably easiest:
|
20
|
+
|
21
|
+
gem install openssl_pkcs8
|
12
22
|
|
13
23
|
== Copyright
|
14
24
|
|
data/VERSION
ADDED
@@ -0,0 +1 @@
|
|
1
|
+
0.1.1
|
@@ -0,0 +1,191 @@
|
|
1
|
+
#include "ruby.h"
|
2
|
+
|
3
|
+
#include <openssl/err.h>
|
4
|
+
#include <openssl/ossl_typ.h>
|
5
|
+
#include <openssl/engine.h>
|
6
|
+
#include <openssl/evp.h>
|
7
|
+
#include <openssl/asn1_mac.h>
|
8
|
+
#include <openssl/x509v3.h>
|
9
|
+
#include <openssl/ssl.h>
|
10
|
+
#include <openssl/pkcs12.h>
|
11
|
+
#include <openssl/pkcs7.h>
|
12
|
+
#include <openssl/hmac.h>
|
13
|
+
#include <openssl/rand.h>
|
14
|
+
#include <openssl/conf.h>
|
15
|
+
#include <openssl/conf_api.h>
|
16
|
+
|
17
|
+
VALUE mOSSL;
|
18
|
+
VALUE mPKey;
|
19
|
+
VALUE cRSA;
|
20
|
+
VALUE eRSAError;
|
21
|
+
VALUE ePKeyError;
|
22
|
+
VALUE eOSSLError;
|
23
|
+
VALUE cCipher;
|
24
|
+
|
25
|
+
#define GetPKey(obj, pkey) do {\
|
26
|
+
Data_Get_Struct(obj, EVP_PKEY, pkey);\
|
27
|
+
if (!pkey) { \
|
28
|
+
rb_raise(rb_eRuntimeError, "PKEY wasn't initialized!");\
|
29
|
+
} \
|
30
|
+
} while (0)
|
31
|
+
#define GetPKeyRSA(obj, pkey) do { \
|
32
|
+
GetPKey(obj, pkey); \
|
33
|
+
if (EVP_PKEY_type(pkey->type) != EVP_PKEY_RSA) { /* PARANOIA? */ \
|
34
|
+
ossl_raise(rb_eRuntimeError, "THIS IS NOT A RSA!") ; \
|
35
|
+
} \
|
36
|
+
} while (0)
|
37
|
+
#define OSSL_PKEY_SET_PRIVATE(obj) rb_iv_set((obj), "private", Qtrue)
|
38
|
+
#define OSSL_PKEY_SET_PUBLIC(obj) rb_iv_set((obj), "private", Qfalse)
|
39
|
+
#define OSSL_PKEY_IS_PRIVATE(obj) (rb_iv_get((obj), "private") == Qtrue)
|
40
|
+
#define RSA_HAS_PRIVATE(rsa) ((rsa)->p && (rsa)->q)
|
41
|
+
#define GetCipher(obj, ctx) do { \
|
42
|
+
Data_Get_Struct(obj, EVP_CIPHER_CTX, ctx); \
|
43
|
+
if (!ctx) { \
|
44
|
+
ossl_raise(rb_eRuntimeError, "Cipher not inititalized!"); \
|
45
|
+
} \
|
46
|
+
} while (0)
|
47
|
+
#define SafeGetCipher(obj, ctx) do { \
|
48
|
+
OSSL_Check_Kind(obj, cCipher); \
|
49
|
+
GetCipher(obj, ctx); \
|
50
|
+
} while (0)
|
51
|
+
|
52
|
+
VALUE ossl_membio2str0(BIO *bio)
|
53
|
+
{
|
54
|
+
VALUE ret;
|
55
|
+
BUF_MEM *buf;
|
56
|
+
|
57
|
+
BIO_get_mem_ptr(bio, &buf);
|
58
|
+
ret = rb_str_new(buf->data, buf->length);
|
59
|
+
|
60
|
+
return ret;
|
61
|
+
}
|
62
|
+
|
63
|
+
VALUE ossl_protect_membio2str(BIO *bio, int *status)
|
64
|
+
{
|
65
|
+
return rb_protect((VALUE(*)_((VALUE)))ossl_membio2str0, (VALUE)bio, status);
|
66
|
+
}
|
67
|
+
|
68
|
+
VALUE ossl_membio2str(BIO *bio)
|
69
|
+
{
|
70
|
+
VALUE ret;
|
71
|
+
int status = 0;
|
72
|
+
|
73
|
+
ret = ossl_protect_membio2str(bio, &status);
|
74
|
+
BIO_free(bio);
|
75
|
+
if(status) rb_jump_tag(status);
|
76
|
+
|
77
|
+
return ret;
|
78
|
+
}
|
79
|
+
|
80
|
+
const EVP_CIPHER* GetCipherPtr(VALUE obj)
|
81
|
+
{
|
82
|
+
EVP_CIPHER_CTX* ctx;
|
83
|
+
|
84
|
+
SafeGetCipher(obj, ctx);
|
85
|
+
|
86
|
+
return EVP_CIPHER_CTX_cipher(ctx);
|
87
|
+
}
|
88
|
+
|
89
|
+
static VALUE openssl_pkcs8_pem_passwd_cb0(VALUE flag)
|
90
|
+
{
|
91
|
+
VALUE pass;
|
92
|
+
|
93
|
+
pass = rb_yield(flag);
|
94
|
+
SafeStringValue(pass);
|
95
|
+
|
96
|
+
return pass;
|
97
|
+
}
|
98
|
+
|
99
|
+
int openssl_pkcs8_pem_passwd_cb(char *buf, int max_len, int flag, void *pwd)
|
100
|
+
{
|
101
|
+
int len, status = 0;
|
102
|
+
VALUE rflag, pass;
|
103
|
+
|
104
|
+
if (pwd || !rb_block_given_p())
|
105
|
+
return PEM_def_callback(buf, max_len, flag, pwd);
|
106
|
+
|
107
|
+
while (1) {
|
108
|
+
/*
|
109
|
+
* when the flag is nonzero, this passphrase
|
110
|
+
* will be used to perform encryption; otherwise it will
|
111
|
+
* be used to perform decryption.
|
112
|
+
*/
|
113
|
+
rflag = flag ? Qtrue : Qfalse;
|
114
|
+
pass = rb_protect(openssl_pkcs8_pem_passwd_cb0, rflag, &status);
|
115
|
+
if (status) return -1; /* exception was raised. */
|
116
|
+
len = (int) RSTRING_LEN(pass);
|
117
|
+
if (len < 4) { /* 4 is OpenSSL hardcoded limit */
|
118
|
+
rb_warning("password must be longer than 4 bytes");
|
119
|
+
continue;
|
120
|
+
}
|
121
|
+
if (len > max_len) {
|
122
|
+
rb_warning("password must be shorter then %d bytes", max_len-1);
|
123
|
+
continue;
|
124
|
+
}
|
125
|
+
memcpy(buf, RSTRING_PTR(pass), len);
|
126
|
+
break;
|
127
|
+
}
|
128
|
+
return len;
|
129
|
+
}
|
130
|
+
|
131
|
+
static VALUE openssl_rsa_to_pem_pkcs8(int argc, VALUE *argv, VALUE self)
|
132
|
+
{
|
133
|
+
EVP_PKEY *pkey;
|
134
|
+
BIO *out;
|
135
|
+
const EVP_CIPHER *ciph = NULL;
|
136
|
+
char *passwd = NULL;
|
137
|
+
VALUE cipher, pass;
|
138
|
+
|
139
|
+
GetPKeyRSA(self, pkey);
|
140
|
+
|
141
|
+
rb_scan_args(argc, argv, "02", &cipher, &pass);
|
142
|
+
|
143
|
+
if (!NIL_P(cipher))
|
144
|
+
{
|
145
|
+
ciph = GetCipherPtr(cipher);
|
146
|
+
if (!NIL_P(pass))
|
147
|
+
{
|
148
|
+
passwd = StringValuePtr(pass);
|
149
|
+
}
|
150
|
+
}
|
151
|
+
|
152
|
+
if (!(out = BIO_new(BIO_s_mem())))
|
153
|
+
{
|
154
|
+
ossl_raise(eRSAError, NULL);
|
155
|
+
}
|
156
|
+
|
157
|
+
if (RSA_HAS_PRIVATE(pkey->pkey.rsa))
|
158
|
+
{
|
159
|
+
if (!PEM_write_bio_PKCS8PrivateKey(
|
160
|
+
out, pkey, ciph,
|
161
|
+
NULL, 0, openssl_pkcs8_pem_passwd_cb, passwd))
|
162
|
+
{
|
163
|
+
BIO_free(out);
|
164
|
+
ossl_raise(eRSAError, NULL);
|
165
|
+
}
|
166
|
+
}
|
167
|
+
else
|
168
|
+
{
|
169
|
+
if (!PEM_write_bio_PUBKEY(out, pkey))
|
170
|
+
{
|
171
|
+
BIO_free(out);
|
172
|
+
ossl_raise(eRSAError, NULL);
|
173
|
+
}
|
174
|
+
}
|
175
|
+
|
176
|
+
return ossl_membio2str(out);
|
177
|
+
}
|
178
|
+
|
179
|
+
void Init_openssl_pkcs8()
|
180
|
+
{
|
181
|
+
mOSSL = rb_const_get(rb_cObject, rb_intern("OpenSSL"));
|
182
|
+
mPKey = rb_const_get(mOSSL, rb_intern("PKey"));
|
183
|
+
cRSA = rb_const_get(mPKey, rb_intern("RSA"));
|
184
|
+
cCipher = rb_const_get(mOSSL, rb_intern("Cipher"));
|
185
|
+
|
186
|
+
eOSSLError = rb_const_get(mOSSL,rb_intern("OpenSSLError"));
|
187
|
+
ePKeyError = rb_const_get(mPKey, rb_intern("PKeyError"));
|
188
|
+
eRSAError = rb_const_get(mPKey, rb_intern("RSAError"));
|
189
|
+
|
190
|
+
rb_define_method(cRSA, "to_pem_pkcs8", openssl_rsa_to_pem_pkcs8, -1);
|
191
|
+
}
|
Binary file
|
data/openssl-pkcs8.o
ADDED
Binary file
|
@@ -0,0 +1,54 @@
|
|
1
|
+
# Generated by jeweler
|
2
|
+
# DO NOT EDIT THIS FILE DIRECTLY
|
3
|
+
# Instead, edit Jeweler::Tasks in Rakefile, and run 'rake gemspec'
|
4
|
+
# -*- encoding: utf-8 -*-
|
5
|
+
|
6
|
+
Gem::Specification.new do |s|
|
7
|
+
s.name = "openssl_pkcs8"
|
8
|
+
s.version = "0.1.1"
|
9
|
+
|
10
|
+
s.required_rubygems_version = Gem::Requirement.new(">= 0") if s.respond_to? :required_rubygems_version=
|
11
|
+
s.authors = ["Scott Tadman"]
|
12
|
+
s.date = "2012-01-16"
|
13
|
+
s.description = "Adds PKCS8 key format support to OpenSSL::PKey::RSA"
|
14
|
+
s.email = "github@tadman.ca"
|
15
|
+
s.extensions = ["ext/openssl_pkcs8/extconf.rb"]
|
16
|
+
s.extra_rdoc_files = [
|
17
|
+
"LICENSE.txt",
|
18
|
+
"README.rdoc"
|
19
|
+
]
|
20
|
+
s.files = [
|
21
|
+
".document",
|
22
|
+
"Gemfile",
|
23
|
+
"LICENSE.txt",
|
24
|
+
"README.rdoc",
|
25
|
+
"Rakefile",
|
26
|
+
"VERSION",
|
27
|
+
"ext/openssl_pkcs8/extconf.rb",
|
28
|
+
"ext/openssl_pkcs8/openssl_pkcs8.c",
|
29
|
+
"ext/openssl_pkcs8/openssl_pkcs8.o",
|
30
|
+
"lib/openssl_pkcs8.rb",
|
31
|
+
"openssl-pkcs8.o",
|
32
|
+
"openssl_pkcs8.gemspec",
|
33
|
+
"test/helper.rb",
|
34
|
+
"test/test_openssl_pkcs8.rb"
|
35
|
+
]
|
36
|
+
s.homepage = "http://github.com/twg/openssl_pkcs8"
|
37
|
+
s.licenses = ["MIT"]
|
38
|
+
s.require_paths = ["lib"]
|
39
|
+
s.rubygems_version = "1.8.11"
|
40
|
+
s.summary = "OpenSSL RSA PKCS8 Extension"
|
41
|
+
|
42
|
+
if s.respond_to? :specification_version then
|
43
|
+
s.specification_version = 3
|
44
|
+
|
45
|
+
if Gem::Version.new(Gem::VERSION) >= Gem::Version.new('1.2.0') then
|
46
|
+
s.add_development_dependency(%q<jeweler>, ["~> 1.6.4"])
|
47
|
+
else
|
48
|
+
s.add_dependency(%q<jeweler>, ["~> 1.6.4"])
|
49
|
+
end
|
50
|
+
else
|
51
|
+
s.add_dependency(%q<jeweler>, ["~> 1.6.4"])
|
52
|
+
end
|
53
|
+
end
|
54
|
+
|
@@ -0,0 +1,24 @@
|
|
1
|
+
require 'helper'
|
2
|
+
|
3
|
+
class TestOpensslPkcs8 < Test::Unit::TestCase
|
4
|
+
def test_rsa_key
|
5
|
+
key = OpenSSL::PKey::RSA.new(1024)
|
6
|
+
|
7
|
+
assert key.respond_to?(:to_pem_pkcs8), "Extension method not defined"
|
8
|
+
|
9
|
+
encoded = key.to_pem_pkcs8
|
10
|
+
|
11
|
+
puts key.to_pem
|
12
|
+
puts encoded
|
13
|
+
|
14
|
+
assert encoded
|
15
|
+
|
16
|
+
encoded_public = key.public_key.to_pem_pkcs8
|
17
|
+
|
18
|
+
puts key.public_key.to_pem
|
19
|
+
puts encoded_public
|
20
|
+
|
21
|
+
assert encoded_public
|
22
|
+
assert encoded_public.match(/BEGIN PUBLIC KEY/)
|
23
|
+
end
|
24
|
+
end
|
metadata
CHANGED
@@ -1,7 +1,7 @@
|
|
1
1
|
--- !ruby/object:Gem::Specification
|
2
2
|
name: openssl_pkcs8
|
3
3
|
version: !ruby/object:Gem::Version
|
4
|
-
version: 0.1.
|
4
|
+
version: 0.1.1
|
5
5
|
prerelease:
|
6
6
|
platform: ruby
|
7
7
|
authors:
|
@@ -13,7 +13,7 @@ date: 2012-01-16 00:00:00.000000000 Z
|
|
13
13
|
dependencies:
|
14
14
|
- !ruby/object:Gem::Dependency
|
15
15
|
name: jeweler
|
16
|
-
requirement: &
|
16
|
+
requirement: &2153224500 !ruby/object:Gem::Requirement
|
17
17
|
none: false
|
18
18
|
requirements:
|
19
19
|
- - ~>
|
@@ -21,7 +21,7 @@ dependencies:
|
|
21
21
|
version: 1.6.4
|
22
22
|
type: :development
|
23
23
|
prerelease: false
|
24
|
-
version_requirements: *
|
24
|
+
version_requirements: *2153224500
|
25
25
|
description: Adds PKCS8 key format support to OpenSSL::PKey::RSA
|
26
26
|
email: github@tadman.ca
|
27
27
|
executables: []
|
@@ -36,8 +36,15 @@ files:
|
|
36
36
|
- LICENSE.txt
|
37
37
|
- README.rdoc
|
38
38
|
- Rakefile
|
39
|
-
-
|
39
|
+
- VERSION
|
40
40
|
- ext/openssl_pkcs8/extconf.rb
|
41
|
+
- ext/openssl_pkcs8/openssl_pkcs8.c
|
42
|
+
- ext/openssl_pkcs8/openssl_pkcs8.o
|
43
|
+
- lib/openssl_pkcs8.rb
|
44
|
+
- openssl-pkcs8.o
|
45
|
+
- openssl_pkcs8.gemspec
|
46
|
+
- test/helper.rb
|
47
|
+
- test/test_openssl_pkcs8.rb
|
41
48
|
homepage: http://github.com/twg/openssl_pkcs8
|
42
49
|
licenses:
|
43
50
|
- MIT
|