Commit
This commit does not belong to any branch on this repository, and may belong to a fork outside of the repository.
Browse files
Browse the repository at this point in the history
First rough cut of PKCS8 exporter
- Loading branch information
Showing
14 changed files
with
292 additions
and
101 deletions.
There are no files selected for viewing
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -1,48 +1,10 @@ | ||
# rcov generated | ||
coverage | ||
|
||
# rdoc generated | ||
rdoc | ||
|
||
# yard generated | ||
doc | ||
.yardoc | ||
|
||
# bundler | ||
.bundle | ||
|
||
# jeweler generated | ||
pkg | ||
|
||
# Have editor/IDE/OS specific files you need to ignore? Consider using a global gitignore: | ||
# | ||
# * Create a file at ~/.gitignore | ||
# * Include files you want ignored | ||
# * Run: git config --global core.excludesfile ~/.gitignore | ||
# | ||
# After doing this, these files will be ignored in all your git projects, | ||
# saving you from having to 'pollute' every project you touch with them | ||
# | ||
# Not sure what to needs to be ignored for particular editors/OSes? Here's some ideas to get you started. (Remember, remove the leading # of the line) | ||
# | ||
# For MacOS: | ||
# | ||
#.DS_Store | ||
|
||
# For TextMate | ||
#*.tmproj | ||
#tmtags | ||
|
||
# For emacs: | ||
#*~ | ||
#\#* | ||
#.\#* | ||
|
||
# For vim: | ||
#*.swp | ||
|
||
# For redcar: | ||
#.redcar | ||
|
||
# For rubinius: | ||
#*.rbc | ||
.DS_Store | ||
*.bundle | ||
Gemfile.lock | ||
Makefile |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -1,13 +1,5 @@ | ||
source "http://rubygems.org" | ||
# Add dependencies required to use your gem here. | ||
# Example: | ||
# gem "activesupport", ">= 2.3.5" | ||
|
||
# Add dependencies to develop your gem here. | ||
# Include everything needed to run rake, tests, features, etc. | ||
group :development do | ||
gem "shoulda", ">= 0" | ||
gem "bundler", "~> 1.0.0" | ||
gem "jeweler", "~> 1.6.4" | ||
gem "rcov", ">= 0" | ||
end |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1 @@ | ||
0.1.0 |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,11 @@ | ||
require 'mkmf' | ||
|
||
extension_name = 'openssl_pkcs8' | ||
|
||
dir_config(extension_name) | ||
|
||
have_header("openssl/ssl.h") | ||
%w[crypto libeay32].any? {|lib| have_library(lib, "OpenSSL_add_all_digests")} | ||
%w[ssl ssleay32].any? {|lib| have_library(lib, "SSL_library_init")} | ||
|
||
create_makefile(extension_name) |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,191 @@ | ||
#include "ruby.h" | ||
|
||
#include <openssl/err.h> | ||
#include <openssl/ossl_typ.h> | ||
#include <openssl/engine.h> | ||
#include <openssl/evp.h> | ||
#include <openssl/asn1_mac.h> | ||
#include <openssl/x509v3.h> | ||
#include <openssl/ssl.h> | ||
#include <openssl/pkcs12.h> | ||
#include <openssl/pkcs7.h> | ||
#include <openssl/hmac.h> | ||
#include <openssl/rand.h> | ||
#include <openssl/conf.h> | ||
#include <openssl/conf_api.h> | ||
|
||
VALUE mOSSL; | ||
VALUE mPKey; | ||
VALUE cRSA; | ||
VALUE eRSAError; | ||
VALUE ePKeyError; | ||
VALUE eOSSLError; | ||
VALUE cCipher; | ||
|
||
#define GetPKey(obj, pkey) do {\ | ||
Data_Get_Struct(obj, EVP_PKEY, pkey);\ | ||
if (!pkey) { \ | ||
rb_raise(rb_eRuntimeError, "PKEY wasn't initialized!");\ | ||
} \ | ||
} while (0) | ||
#define GetPKeyRSA(obj, pkey) do { \ | ||
GetPKey(obj, pkey); \ | ||
if (EVP_PKEY_type(pkey->type) != EVP_PKEY_RSA) { /* PARANOIA? */ \ | ||
ossl_raise(rb_eRuntimeError, "THIS IS NOT A RSA!") ; \ | ||
} \ | ||
} while (0) | ||
#define OSSL_PKEY_SET_PRIVATE(obj) rb_iv_set((obj), "private", Qtrue) | ||
#define OSSL_PKEY_SET_PUBLIC(obj) rb_iv_set((obj), "private", Qfalse) | ||
#define OSSL_PKEY_IS_PRIVATE(obj) (rb_iv_get((obj), "private") == Qtrue) | ||
#define RSA_HAS_PRIVATE(rsa) ((rsa)->p && (rsa)->q) | ||
#define GetCipher(obj, ctx) do { \ | ||
Data_Get_Struct(obj, EVP_CIPHER_CTX, ctx); \ | ||
if (!ctx) { \ | ||
ossl_raise(rb_eRuntimeError, "Cipher not inititalized!"); \ | ||
} \ | ||
} while (0) | ||
#define SafeGetCipher(obj, ctx) do { \ | ||
OSSL_Check_Kind(obj, cCipher); \ | ||
GetCipher(obj, ctx); \ | ||
} while (0) | ||
|
||
VALUE ossl_membio2str0(BIO *bio) | ||
{ | ||
VALUE ret; | ||
BUF_MEM *buf; | ||
|
||
BIO_get_mem_ptr(bio, &buf); | ||
ret = rb_str_new(buf->data, buf->length); | ||
|
||
return ret; | ||
} | ||
|
||
VALUE ossl_protect_membio2str(BIO *bio, int *status) | ||
{ | ||
return rb_protect((VALUE(*)_((VALUE)))ossl_membio2str0, (VALUE)bio, status); | ||
} | ||
|
||
VALUE ossl_membio2str(BIO *bio) | ||
{ | ||
VALUE ret; | ||
int status = 0; | ||
|
||
ret = ossl_protect_membio2str(bio, &status); | ||
BIO_free(bio); | ||
if(status) rb_jump_tag(status); | ||
|
||
return ret; | ||
} | ||
|
||
const EVP_CIPHER* GetCipherPtr(VALUE obj) | ||
{ | ||
EVP_CIPHER_CTX* ctx; | ||
|
||
SafeGetCipher(obj, ctx); | ||
|
||
return EVP_CIPHER_CTX_cipher(ctx); | ||
} | ||
|
||
static VALUE openssl_pkcs8_pem_passwd_cb0(VALUE flag) | ||
{ | ||
VALUE pass; | ||
|
||
pass = rb_yield(flag); | ||
SafeStringValue(pass); | ||
|
||
return pass; | ||
} | ||
|
||
int openssl_pkcs8_pem_passwd_cb(char *buf, int max_len, int flag, void *pwd) | ||
{ | ||
int len, status = 0; | ||
VALUE rflag, pass; | ||
|
||
if (pwd || !rb_block_given_p()) | ||
return PEM_def_callback(buf, max_len, flag, pwd); | ||
|
||
while (1) { | ||
/* | ||
* when the flag is nonzero, this passphrase | ||
* will be used to perform encryption; otherwise it will | ||
* be used to perform decryption. | ||
*/ | ||
rflag = flag ? Qtrue : Qfalse; | ||
pass = rb_protect(openssl_pkcs8_pem_passwd_cb0, rflag, &status); | ||
if (status) return -1; /* exception was raised. */ | ||
len = (int) RSTRING_LEN(pass); | ||
if (len < 4) { /* 4 is OpenSSL hardcoded limit */ | ||
rb_warning("password must be longer than 4 bytes"); | ||
continue; | ||
} | ||
if (len > max_len) { | ||
rb_warning("password must be shorter then %d bytes", max_len-1); | ||
continue; | ||
} | ||
memcpy(buf, RSTRING_PTR(pass), len); | ||
break; | ||
} | ||
return len; | ||
} | ||
|
||
static VALUE openssl_rsa_to_pem_pkcs8(int argc, VALUE *argv, VALUE self) | ||
{ | ||
EVP_PKEY *pkey; | ||
BIO *out; | ||
const EVP_CIPHER *ciph = NULL; | ||
char *passwd = NULL; | ||
VALUE cipher, pass; | ||
|
||
GetPKeyRSA(self, pkey); | ||
|
||
rb_scan_args(argc, argv, "02", &cipher, &pass); | ||
|
||
if (!NIL_P(cipher)) | ||
{ | ||
ciph = GetCipherPtr(cipher); | ||
if (!NIL_P(pass)) | ||
{ | ||
passwd = StringValuePtr(pass); | ||
} | ||
} | ||
|
||
if (!(out = BIO_new(BIO_s_mem()))) | ||
{ | ||
ossl_raise(eRSAError, NULL); | ||
} | ||
|
||
if (RSA_HAS_PRIVATE(pkey->pkey.rsa)) | ||
{ | ||
if (!PEM_write_bio_PKCS8PrivateKey( | ||
out, pkey, ciph, | ||
NULL, 0, openssl_pkcs8_pem_passwd_cb, passwd)) | ||
{ | ||
BIO_free(out); | ||
ossl_raise(eRSAError, NULL); | ||
} | ||
} | ||
else | ||
{ | ||
if (!PEM_write_bio_PUBKEY(out, pkey)) | ||
{ | ||
BIO_free(out); | ||
ossl_raise(eRSAError, NULL); | ||
} | ||
} | ||
|
||
return ossl_membio2str(out); | ||
} | ||
|
||
void Init_openssl_pkcs8() | ||
{ | ||
mOSSL = rb_const_get(rb_cObject, rb_intern("OpenSSL")); | ||
mPKey = rb_const_get(mOSSL, rb_intern("PKey")); | ||
cRSA = rb_const_get(mPKey, rb_intern("RSA")); | ||
cCipher = rb_const_get(mOSSL, rb_intern("Cipher")); | ||
|
||
eOSSLError = rb_const_get(mOSSL,rb_intern("OpenSSLError")); | ||
ePKeyError = rb_const_get(mPKey, rb_intern("PKeyError")); | ||
eRSAError = rb_const_get(mPKey, rb_intern("RSAError")); | ||
|
||
rb_define_method(cRSA, "to_pem_pkcs8", openssl_rsa_to_pem_pkcs8, -1); | ||
} |
Binary file not shown.
Empty file.
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,3 @@ | ||
require 'openssl' | ||
|
||
require 'openssl_pkcs8/openssl_pkcs8' |
Binary file not shown.
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,46 @@ | ||
# Generated by jeweler | ||
# DO NOT EDIT THIS FILE DIRECTLY | ||
# Instead, edit Jeweler::Tasks in Rakefile, and run 'rake gemspec' | ||
# -*- encoding: utf-8 -*- | ||
|
||
Gem::Specification.new do |s| | ||
s.name = "openssl_pkcs8" | ||
s.version = "0.1.0" | ||
|
||
s.required_rubygems_version = Gem::Requirement.new(">= 0") if s.respond_to? :required_rubygems_version= | ||
s.authors = ["Scott Tadman"] | ||
s.date = "2012-01-16" | ||
s.description = "Adds PKCS8 key format support to OpenSSL::PKey::RSA" | ||
s.email = "github@tadman.ca" | ||
s.extensions = ["ext/openssl_pkcs8/extconf.rb"] | ||
s.extra_rdoc_files = [ | ||
"LICENSE.txt", | ||
"README.rdoc" | ||
] | ||
s.files = [ | ||
".document", | ||
"Gemfile", | ||
"LICENSE.txt", | ||
"README.rdoc", | ||
"Rakefile", | ||
"test/helper.rb" | ||
] | ||
s.homepage = "http://github.com/twg/openssl_pkcs8" | ||
s.licenses = ["MIT"] | ||
s.require_paths = ["lib"] | ||
s.rubygems_version = "1.8.11" | ||
s.summary = "OpenSSL RSA PKCS8 Extension" | ||
|
||
if s.respond_to? :specification_version then | ||
s.specification_version = 3 | ||
|
||
if Gem::Version.new(Gem::VERSION) >= Gem::Version.new('1.2.0') then | ||
s.add_development_dependency(%q<jeweler>, ["~> 1.6.4"]) | ||
else | ||
s.add_dependency(%q<jeweler>, ["~> 1.6.4"]) | ||
end | ||
else | ||
s.add_dependency(%q<jeweler>, ["~> 1.6.4"]) | ||
end | ||
end | ||
|
Oops, something went wrong.