зеркало из https://github.com/github/ruby.git
openssl: add missing #to_der to OCSP::{CertificateId,BasicResponse}
* ext/openssl/ossl_ocsp.c (ossl_ocspbres_to_der, ossl_ocspcid_to_der): Implement #to_der methods for OCSP::BasicResponse and OCSP::CertificateId. (ossl_ocspreq_initialize, ossl_ocspres_initialize): Use GetOCSP*() instead of raw DATA_PTR(). (ossl_ocspbres_initialize, ossl_ocspcid_initialize): Allow initializing from DER string. (Init_ossl_ocsp): Define new #to_der methods. * test/openssl/test_ocsp.rb: Test these changes. Also add missing tests for OCSP::{Response,Request}#to_der. git-svn-id: svn+ssh://ci.ruby-lang.org/ruby/trunk@55409 b2dd03c8-39d4-4d8f-98ff-823fe69b080e
This commit is contained in:
Родитель
8dd0a046a9
Коммит
40799e5ef9
17
ChangeLog
17
ChangeLog
|
@ -1,3 +1,20 @@
|
|||
Tue Jun 14 21:40:42 2016 Kazuki Yamaguchi <k@rhe.jp>
|
||||
|
||||
* ext/openssl/ossl_ocsp.c (ossl_ocspbres_to_der, ossl_ocspcid_to_der):
|
||||
Implement #to_der methods for OCSP::BasicResponse and
|
||||
OCSP::CertificateId.
|
||||
|
||||
(ossl_ocspreq_initialize, ossl_ocspres_initialize): Use GetOCSP*()
|
||||
instead of raw DATA_PTR().
|
||||
|
||||
(ossl_ocspbres_initialize, ossl_ocspcid_initialize): Allow
|
||||
initializing from DER string.
|
||||
|
||||
(Init_ossl_ocsp): Define new #to_der methods.
|
||||
|
||||
* test/openssl/test_ocsp.rb: Test these changes. Also add missing tests
|
||||
for OCSP::{Response,Request}#to_der.
|
||||
|
||||
Tue Jun 14 21:35:00 2016 Kazuki Yamaguchi <k@rhe.jp>
|
||||
|
||||
* ext/openssl/openssl_missing.h (DH_set0_pqg, RSA_set0_key):
|
||||
|
|
|
@ -180,15 +180,13 @@ ossl_ocspreq_initialize(int argc, VALUE *argv, VALUE self)
|
|||
|
||||
rb_scan_args(argc, argv, "01", &arg);
|
||||
if(!NIL_P(arg)){
|
||||
OCSP_REQUEST *req = DATA_PTR(self), *x;
|
||||
OCSP_REQUEST *req;
|
||||
GetOCSPReq(self, req);
|
||||
arg = ossl_to_der_if_possible(arg);
|
||||
StringValue(arg);
|
||||
p = (unsigned char*)RSTRING_PTR(arg);
|
||||
x = d2i_OCSP_REQUEST(&req, &p, RSTRING_LEN(arg));
|
||||
DATA_PTR(self) = req;
|
||||
if(!x){
|
||||
p = (unsigned char *)RSTRING_PTR(arg);
|
||||
if (!d2i_OCSP_REQUEST(&req, &p, RSTRING_LEN(arg)))
|
||||
ossl_raise(eOCSPError, "cannot load DER encoded request");
|
||||
}
|
||||
}
|
||||
|
||||
return self;
|
||||
|
@ -463,15 +461,13 @@ ossl_ocspres_initialize(int argc, VALUE *argv, VALUE self)
|
|||
|
||||
rb_scan_args(argc, argv, "01", &arg);
|
||||
if(!NIL_P(arg)){
|
||||
OCSP_RESPONSE *res = DATA_PTR(self), *x;
|
||||
OCSP_RESPONSE *res;
|
||||
GetOCSPRes(self, res);
|
||||
arg = ossl_to_der_if_possible(arg);
|
||||
StringValue(arg);
|
||||
p = (unsigned char *)RSTRING_PTR(arg);
|
||||
x = d2i_OCSP_RESPONSE(&res, &p, RSTRING_LEN(arg));
|
||||
DATA_PTR(self) = res;
|
||||
if(!x){
|
||||
if (!d2i_OCSP_RESPONSE(&res, &p, RSTRING_LEN(arg)))
|
||||
ossl_raise(eOCSPError, "cannot load DER encoded response");
|
||||
}
|
||||
}
|
||||
|
||||
return self;
|
||||
|
@ -584,14 +580,29 @@ ossl_ocspbres_alloc(VALUE klass)
|
|||
|
||||
/*
|
||||
* call-seq:
|
||||
* OpenSSL::OCSP::BasicResponse.new(*) -> basic_response
|
||||
* OpenSSL::OCSP::BasicResponse.new(der_string = nil) -> basic_response
|
||||
*
|
||||
* Creates a new BasicResponse and ignores all arguments.
|
||||
* Creates a new BasicResponse. If +der_string+ is given, decodes +der_string+
|
||||
* as DER.
|
||||
*/
|
||||
|
||||
static VALUE
|
||||
ossl_ocspbres_initialize(int argc, VALUE *argv, VALUE self)
|
||||
{
|
||||
VALUE arg;
|
||||
const unsigned char *p;
|
||||
|
||||
rb_scan_args(argc, argv, "01", &arg);
|
||||
if (!NIL_P(arg)) {
|
||||
OCSP_BASICRESP *res;
|
||||
GetOCSPBasicRes(self, res);
|
||||
arg = ossl_to_der_if_possible(arg);
|
||||
StringValue(arg);
|
||||
p = (unsigned char *)RSTRING_PTR(arg);
|
||||
if (!d2i_OCSP_BASICRESP(&res, &p, RSTRING_LEN(arg)))
|
||||
ossl_raise(eOCSPError, "d2i_OCSP_BASICRESP");
|
||||
}
|
||||
|
||||
return self;
|
||||
}
|
||||
|
||||
|
@ -855,6 +866,32 @@ ossl_ocspbres_verify(int argc, VALUE *argv, VALUE self)
|
|||
return result;
|
||||
}
|
||||
|
||||
/*
|
||||
* call-seq:
|
||||
* basic_response.to_der -> String
|
||||
*
|
||||
* Encodes this basic response into a DER-encoded string.
|
||||
*/
|
||||
static VALUE
|
||||
ossl_ocspbres_to_der(VALUE self)
|
||||
{
|
||||
OCSP_BASICRESP *res;
|
||||
VALUE str;
|
||||
long len;
|
||||
unsigned char *p;
|
||||
|
||||
GetOCSPBasicRes(self, res);
|
||||
if ((len = i2d_OCSP_BASICRESP(res, NULL)) <= 0)
|
||||
ossl_raise(eOCSPError, NULL);
|
||||
str = rb_str_new(0, len);
|
||||
p = (unsigned char *)RSTRING_PTR(str);
|
||||
if (i2d_OCSP_BASICRESP(res, &p) <= 0)
|
||||
ossl_raise(eOCSPError, NULL);
|
||||
ossl_str_adjust(str, p);
|
||||
|
||||
return str;
|
||||
}
|
||||
|
||||
/*
|
||||
* OCSP::CertificateId
|
||||
*/
|
||||
|
@ -875,10 +912,14 @@ ossl_ocspcid_alloc(VALUE klass)
|
|||
/*
|
||||
* call-seq:
|
||||
* OpenSSL::OCSP::CertificateId.new(subject, issuer, digest = nil) -> certificate_id
|
||||
* OpenSSL::OCSP::CertificateId.new(der_string) -> certificate_id
|
||||
*
|
||||
* Creates a new OpenSSL::OCSP::CertificateId for the given +subject+ and
|
||||
* +issuer+ X509 certificates. The +digest+ is used to compute the
|
||||
* certificate ID and must be an OpenSSL::Digest instance.
|
||||
*
|
||||
* If only one argument is given, decodes it as DER representation of a
|
||||
* certificate ID.
|
||||
*/
|
||||
|
||||
static VALUE
|
||||
|
@ -889,7 +930,17 @@ ossl_ocspcid_initialize(int argc, VALUE *argv, VALUE self)
|
|||
VALUE subject, issuer, digest;
|
||||
const EVP_MD *md;
|
||||
|
||||
if (rb_scan_args(argc, argv, "21", &subject, &issuer, &digest) == 0) {
|
||||
GetOCSPCertId(self, id);
|
||||
if (rb_scan_args(argc, argv, "12", &subject, &issuer, &digest) == 1) {
|
||||
VALUE arg;
|
||||
const unsigned char *p;
|
||||
|
||||
arg = ossl_to_der_if_possible(subject);
|
||||
StringValue(arg);
|
||||
p = (unsigned char *)RSTRING_PTR(arg);
|
||||
if (!d2i_OCSP_CERTID(&id, &p, RSTRING_LEN(arg)))
|
||||
ossl_raise(eOCSPError, "d2i_OCSP_CERTID");
|
||||
|
||||
return self;
|
||||
}
|
||||
|
||||
|
@ -904,9 +955,8 @@ ossl_ocspcid_initialize(int argc, VALUE *argv, VALUE self)
|
|||
}
|
||||
if(!newid)
|
||||
ossl_raise(eOCSPError, NULL);
|
||||
GetOCSPCertId(self, id);
|
||||
OCSP_CERTID_free(id);
|
||||
RDATA(self)->data = newid;
|
||||
SetOCSPCertId(self, newid);
|
||||
|
||||
return self;
|
||||
}
|
||||
|
@ -971,6 +1021,32 @@ ossl_ocspcid_get_serial(VALUE self)
|
|||
return asn1integer_to_num(serial);
|
||||
}
|
||||
|
||||
/*
|
||||
* call-seq:
|
||||
* certificate_id.to_der -> String
|
||||
*
|
||||
* Encodes this certificate identifier into a DER-encoded string.
|
||||
*/
|
||||
static VALUE
|
||||
ossl_ocspcid_to_der(VALUE self)
|
||||
{
|
||||
OCSP_CERTID *id;
|
||||
VALUE str;
|
||||
long len;
|
||||
unsigned char *p;
|
||||
|
||||
GetOCSPCertId(self, id);
|
||||
if ((len = i2d_OCSP_CERTID(id, NULL)) <= 0)
|
||||
ossl_raise(eOCSPError, NULL);
|
||||
str = rb_str_new(0, len);
|
||||
p = (unsigned char *)RSTRING_PTR(str);
|
||||
if (i2d_OCSP_CERTID(id, &p) <= 0)
|
||||
ossl_raise(eOCSPError, NULL);
|
||||
ossl_str_adjust(str, p);
|
||||
|
||||
return str;
|
||||
}
|
||||
|
||||
void
|
||||
Init_ossl_ocsp(void)
|
||||
{
|
||||
|
@ -1138,6 +1214,7 @@ Init_ossl_ocsp(void)
|
|||
rb_define_method(cOCSPBasicRes, "status", ossl_ocspbres_get_status, 0);
|
||||
rb_define_method(cOCSPBasicRes, "sign", ossl_ocspbres_sign, -1);
|
||||
rb_define_method(cOCSPBasicRes, "verify", ossl_ocspbres_verify, -1);
|
||||
rb_define_method(cOCSPBasicRes, "to_der", ossl_ocspbres_to_der, 0);
|
||||
|
||||
/*
|
||||
* An OpenSSL::OCSP::CertificateId identifies a certificate to the CA so
|
||||
|
@ -1150,6 +1227,7 @@ Init_ossl_ocsp(void)
|
|||
rb_define_method(cOCSPCertId, "cmp", ossl_ocspcid_cmp, 1);
|
||||
rb_define_method(cOCSPCertId, "cmp_issuer", ossl_ocspcid_cmp_issuer, 1);
|
||||
rb_define_method(cOCSPCertId, "serial", ossl_ocspcid_get_serial, 0);
|
||||
rb_define_method(cOCSPCertId, "to_der", ossl_ocspcid_to_der, 0);
|
||||
|
||||
/* Internal error in issuer */
|
||||
rb_define_const(mOCSP, "RESPONSE_STATUS_INTERNALERROR", INT2NUM(OCSP_RESPONSE_STATUS_INTERNALERROR));
|
||||
|
|
|
@ -8,6 +8,10 @@ class OpenSSL::TestOCSP < OpenSSL::TestCase
|
|||
ca_subj = OpenSSL::X509::Name.parse("/DC=org/DC=ruby-lang/CN=TestCA")
|
||||
ca_key = OpenSSL::TestUtils::TEST_KEY_RSA1024
|
||||
ca_serial = 0xabcabcabcabc
|
||||
ca_exts = [
|
||||
["basicConstraints", "CA:TRUE", true],
|
||||
["keyUsage", "cRLSign,keyCertSign", true],
|
||||
]
|
||||
|
||||
subj = OpenSSL::X509::Name.parse("/DC=org/DC=ruby-lang/CN=TestCert")
|
||||
@key = OpenSSL::TestUtils::TEST_KEY_RSA1024
|
||||
|
@ -17,9 +21,17 @@ class OpenSSL::TestOCSP < OpenSSL::TestCase
|
|||
dgst = OpenSSL::Digest::SHA1.new
|
||||
|
||||
@ca_cert = OpenSSL::TestUtils.issue_cert(
|
||||
ca_subj, ca_key, ca_serial, now, now+3600, [], nil, nil, dgst)
|
||||
ca_subj, ca_key, ca_serial, now, now+3600, ca_exts, nil, nil, dgst)
|
||||
@cert = OpenSSL::TestUtils.issue_cert(
|
||||
subj, @key, serial, now, now+3600, [], @ca_cert, nil, dgst)
|
||||
subj, @key, serial, now, now+3600, [], @ca_cert, ca_key, dgst)
|
||||
|
||||
@key2 = OpenSSL::TestUtils::TEST_KEY_RSA2048
|
||||
cert2_exts = [
|
||||
["extendedKeyUsage", "OCSPSigning", true],
|
||||
]
|
||||
@cert2 = OpenSSL::TestUtils.issue_cert(
|
||||
OpenSSL::X509::Name.parse("/DC=org/DC=ruby-lang/CN=TestCert2"),
|
||||
@key2, serial+1, now, now+3600, cert2_exts, @ca_cert, ca_key, "SHA256")
|
||||
end
|
||||
|
||||
def test_new_certificate_id
|
||||
|
@ -34,6 +46,30 @@ class OpenSSL::TestOCSP < OpenSSL::TestCase
|
|||
assert_equal @cert.serial, cid.serial
|
||||
end if defined?(OpenSSL::Digest::SHA256)
|
||||
|
||||
def test_certificate_id_der
|
||||
cid = OpenSSL::OCSP::CertificateId.new(@cert, @ca_cert) # hash algorithm defaults to SHA-1
|
||||
der = cid.to_der
|
||||
asn1 = OpenSSL::ASN1.decode(der)
|
||||
assert_equal OpenSSL::ASN1.ObjectId("SHA1").to_der, asn1.value[0].value[0].to_der
|
||||
assert_equal OpenSSL::Digest::SHA1.digest(@cert.issuer.to_der), asn1.value[1].value
|
||||
assert_equal OpenSSL::Digest::SHA1.digest(OpenSSL::ASN1.decode(@ca_cert.to_der).value[0].value[6].value[1].value), asn1.value[2].value
|
||||
assert_equal @cert.serial, asn1.value[3].value
|
||||
assert_equal der, OpenSSL::OCSP::CertificateId.new(der).to_der
|
||||
end
|
||||
|
||||
def test_request_der
|
||||
request = OpenSSL::OCSP::Request.new
|
||||
cid = OpenSSL::OCSP::CertificateId.new(@cert, @ca_cert, OpenSSL::Digest::SHA1.new)
|
||||
request.add_certid(cid)
|
||||
request.sign(@cert, @key, [@ca_cert], 0)
|
||||
asn1 = OpenSSL::ASN1.decode(request.to_der)
|
||||
assert_equal cid.to_der, asn1.value[0].value.find { |a| a.tag_class == :UNIVERSAL }.value[0].value[0].to_der
|
||||
assert_equal OpenSSL::ASN1.ObjectId("sha1WithRSAEncryption").to_der, asn1.value[1].value[0].value[0].value[0].to_der
|
||||
assert_equal @cert.to_der, asn1.value[1].value[0].value[2].value[0].value[0].to_der
|
||||
assert_equal @ca_cert.to_der, asn1.value[1].value[0].value[2].value[0].value[1].to_der
|
||||
assert_equal asn1.to_der, OpenSSL::OCSP::Request.new(asn1.to_der).to_der
|
||||
end
|
||||
|
||||
def test_new_ocsp_request
|
||||
request = OpenSSL::OCSP::Request.new
|
||||
cid = OpenSSL::OCSP::CertificateId.new(@cert, @ca_cert, OpenSSL::Digest::SHA1.new)
|
||||
|
@ -43,6 +79,33 @@ class OpenSSL::TestOCSP < OpenSSL::TestCase
|
|||
# in current implementation not same instance of certificate id, but should contain same data
|
||||
assert_equal cid.serial, request.certid.first.serial
|
||||
end
|
||||
|
||||
def test_basic_response_der
|
||||
bres = OpenSSL::OCSP::BasicResponse.new
|
||||
cid = OpenSSL::OCSP::CertificateId.new(@cert, @ca_cert, OpenSSL::Digest::SHA1.new)
|
||||
bres.add_status(cid, OpenSSL::OCSP::V_CERTSTATUS_GOOD, 0, nil, -300, 500, [])
|
||||
bres.add_nonce("NONCE")
|
||||
bres.sign(@cert2, @key2, [@ca_cert], 0)
|
||||
der = bres.to_der
|
||||
asn1 = OpenSSL::ASN1.decode(der)
|
||||
assert_equal cid.to_der, asn1.value[0].value.find { |a| a.class == OpenSSL::ASN1::Sequence }.value[0].value[0].to_der
|
||||
assert_equal OpenSSL::ASN1.Sequence([@cert2, @ca_cert]).to_der, asn1.value[3].value[0].to_der
|
||||
assert_equal der, OpenSSL::OCSP::BasicResponse.new(der).to_der
|
||||
end
|
||||
|
||||
def test_response_der
|
||||
bres = OpenSSL::OCSP::BasicResponse.new
|
||||
cid = OpenSSL::OCSP::CertificateId.new(@cert, @ca_cert, OpenSSL::Digest::SHA1.new)
|
||||
bres.add_status(cid, OpenSSL::OCSP::V_CERTSTATUS_GOOD, 0, nil, -300, 500, [])
|
||||
bres.sign(@cert2, @key2, [@ca_cert], 0)
|
||||
res = OpenSSL::OCSP::Response.create(OpenSSL::OCSP::RESPONSE_STATUS_SUCCESSFUL, bres)
|
||||
der = res.to_der
|
||||
asn1 = OpenSSL::ASN1.decode(der)
|
||||
assert_equal OpenSSL::OCSP::RESPONSE_STATUS_SUCCESSFUL, asn1.value[0].value
|
||||
assert_equal OpenSSL::ASN1.ObjectId("basicOCSPResponse").to_der, asn1.value[1].value[0].value[0].to_der
|
||||
assert_equal bres.to_der, asn1.value[1].value[0].value[1].value
|
||||
assert_equal der, OpenSSL::OCSP::Response.new(der).to_der
|
||||
end
|
||||
end
|
||||
|
||||
end
|
||||
|
|
Загрузка…
Ссылка в новой задаче