mirror of
https://github.com/ruby/ruby.git
synced 2022-11-09 12:17:21 -05:00
766 lines
20 KiB
C
766 lines
20 KiB
C
|
/*
|
||
|
* $Id$
|
||
|
* 'OpenSSL for Ruby' project
|
||
|
* Copyright (C) 2003 Michal Rokos <m.rokos@sh.cvut.cz>
|
||
|
* Copyright (C) 2003 GOTOU Yuuzou <gotoyuzo@notwork.org>
|
||
|
* All rights reserved.
|
||
|
*/
|
||
|
/*
|
||
|
* This program is licenced under the same licence as Ruby.
|
||
|
* (See the file 'LICENCE'.)
|
||
|
*/
|
||
|
#include "ossl.h"
|
||
|
|
||
|
#if defined(OSSL_OCSP_ENABLED)
|
||
|
|
||
|
#define WrapOCSPReq(klass, obj, req) do { \
|
||
|
if(!req) ossl_raise(rb_eRuntimeError, "Request wasn't initialized!"); \
|
||
|
obj = Data_Wrap_Struct(klass, 0, OCSP_REQUEST_free, req); \
|
||
|
} while (0)
|
||
|
#define GetOCSPReq(obj, req) do { \
|
||
|
Data_Get_Struct(obj, OCSP_REQUEST, req); \
|
||
|
if(!req) ossl_raise(rb_eRuntimeError, "Request wasn't initialized!"); \
|
||
|
} while (0)
|
||
|
#define SafeGetOCSPReq(obj, req) do { \
|
||
|
OSSL_Check_Kind(obj, cOCSPReq); \
|
||
|
GetOCSPReq(obj, req); \
|
||
|
} while (0)
|
||
|
|
||
|
#define WrapOCSPRes(klass, obj, res) do { \
|
||
|
if(!res) ossl_raise(rb_eRuntimeError, "Response wasn't initialized!"); \
|
||
|
obj = Data_Wrap_Struct(klass, 0, OCSP_RESPONSE_free, res); \
|
||
|
} while (0)
|
||
|
#define GetOCSPRes(obj, res) do { \
|
||
|
Data_Get_Struct(obj, OCSP_RESPONSE, res); \
|
||
|
if(!res) ossl_raise(rb_eRuntimeError, "Response wasn't initialized!"); \
|
||
|
} while (0)
|
||
|
#define SafeGetOCSPRes(obj, res) do { \
|
||
|
OSSL_Check_Kind(obj, cOCSPRes); \
|
||
|
GetOCSPRes(obj, res); \
|
||
|
} while (0)
|
||
|
|
||
|
#define WrapOCSPBasicRes(klass, obj, res) do { \
|
||
|
if(!res) ossl_raise(rb_eRuntimeError, "Response wasn't initialized!"); \
|
||
|
obj = Data_Wrap_Struct(klass, 0, OCSP_BASICRESP_free, res); \
|
||
|
} while (0)
|
||
|
#define GetOCSPBasicRes(obj, res) do { \
|
||
|
Data_Get_Struct(obj, OCSP_BASICRESP, res); \
|
||
|
if(!res) ossl_raise(rb_eRuntimeError, "Response wasn't initialized!"); \
|
||
|
} while (0)
|
||
|
#define SafeGetOCSPBasicRes(obj, res) do { \
|
||
|
OSSL_Check_Kind(obj, cOCSPBasicRes); \
|
||
|
GetOCSPBasicRes(obj, res); \
|
||
|
} while (0)
|
||
|
|
||
|
#define WrapOCSPCertId(klass, obj, cid) do { \
|
||
|
if(!cid) ossl_raise(rb_eRuntimeError, "Cert ID wasn't initialized!"); \
|
||
|
obj = Data_Wrap_Struct(klass, 0, OCSP_CERTID_free, cid); \
|
||
|
} while (0)
|
||
|
#define GetOCSPCertId(obj, cid) do { \
|
||
|
Data_Get_Struct(obj, OCSP_CERTID, cid); \
|
||
|
if(!cid) ossl_raise(rb_eRuntimeError, "Cert ID wasn't initialized!"); \
|
||
|
} while (0)
|
||
|
#define SafeGetOCSPCertId(obj, cid) do { \
|
||
|
OSSL_Check_Kind(obj, cOCSPCertId); \
|
||
|
GetOCSPCertId(obj, cid); \
|
||
|
} while (0)
|
||
|
|
||
|
VALUE mOCSP;
|
||
|
VALUE eOCSPError;
|
||
|
VALUE cOCSPReq;
|
||
|
VALUE cOCSPRes;
|
||
|
VALUE cOCSPBasicRes;
|
||
|
VALUE cOCSPCertId;
|
||
|
|
||
|
/*
|
||
|
* Public
|
||
|
*/
|
||
|
static VALUE
|
||
|
ossl_ocspcertid_new(OCSP_CERTID *cid)
|
||
|
{
|
||
|
VALUE obj;
|
||
|
WrapOCSPCertId(cOCSPCertId, obj, cid);
|
||
|
return obj;
|
||
|
}
|
||
|
|
||
|
/*
|
||
|
* OCSP::Resquest
|
||
|
*/
|
||
|
static VALUE
|
||
|
ossl_ocspreq_alloc(VALUE klass)
|
||
|
{
|
||
|
OCSP_REQUEST *req;
|
||
|
VALUE obj;
|
||
|
|
||
|
if (!(req = OCSP_REQUEST_new()))
|
||
|
ossl_raise(eOCSPError, NULL);
|
||
|
WrapOCSPReq(klass, obj, req);
|
||
|
|
||
|
return obj;
|
||
|
}
|
||
|
DEFINE_ALLOC_WRAPPER(ossl_ocspreq_alloc)
|
||
|
|
||
|
static VALUE
|
||
|
ossl_ocspreq_initialize(int argc, VALUE *argv, VALUE self)
|
||
|
{
|
||
|
VALUE arg;
|
||
|
BIO *bio;
|
||
|
|
||
|
rb_scan_args(argc, argv, "01", &arg);
|
||
|
if(!NIL_P(arg)){
|
||
|
bio = ossl_obj2bio(arg);
|
||
|
if(!d2i_OCSP_REQUEST_bio(bio, (OCSP_REQUEST**)&DATA_PTR(self))){
|
||
|
BIO_free(bio);
|
||
|
ossl_raise(eOCSPError, "cannot load DER encoded request");
|
||
|
}
|
||
|
BIO_free(bio);
|
||
|
}
|
||
|
|
||
|
return self;
|
||
|
}
|
||
|
|
||
|
static VALUE
|
||
|
ossl_ocspreq_add_nonce(int argc, VALUE *argv, VALUE self)
|
||
|
{
|
||
|
OCSP_REQUEST *req;
|
||
|
VALUE val;
|
||
|
int ret;
|
||
|
|
||
|
rb_scan_args(argc, argv, "01", &val);
|
||
|
GetOCSPReq(self, req);
|
||
|
if(NIL_P(val))
|
||
|
ret = OCSP_request_add1_nonce(req, NULL, -1);
|
||
|
else{
|
||
|
StringValue(val);
|
||
|
ret = OCSP_request_add1_nonce(req, RSTRING(val)->ptr, RSTRING(val)->len);
|
||
|
}
|
||
|
if(!ret) ossl_raise(eOCSPError, NULL);
|
||
|
|
||
|
return self;
|
||
|
}
|
||
|
|
||
|
/* Check nonce validity in a request and response.
|
||
|
* Return value reflects result:
|
||
|
* 1: nonces present and equal.
|
||
|
* 2: nonces both absent.
|
||
|
* 3: nonce present in response only.
|
||
|
* 0: nonces both present and not equal.
|
||
|
* -1: nonce in request only.
|
||
|
*
|
||
|
* For most responders clients can check return > 0.
|
||
|
* If responder doesn't handle nonces return != 0 may be
|
||
|
* necessary. return == 0 is always an error.
|
||
|
*/
|
||
|
static VALUE
|
||
|
ossl_ocspreq_check_nonce(VALUE self, VALUE basic_resp)
|
||
|
{
|
||
|
OCSP_REQUEST *req;
|
||
|
OCSP_BASICRESP *bs;
|
||
|
int res;
|
||
|
|
||
|
GetOCSPReq(self, req);
|
||
|
SafeGetOCSPBasicRes(basic_resp, bs);
|
||
|
res = OCSP_check_nonce(req, bs);
|
||
|
|
||
|
return INT2NUM(res);
|
||
|
}
|
||
|
|
||
|
static VALUE
|
||
|
ossl_ocspreq_add_certid(VALUE self, VALUE certid)
|
||
|
{
|
||
|
OCSP_REQUEST *req;
|
||
|
OCSP_CERTID *id;
|
||
|
|
||
|
GetOCSPReq(self, req);
|
||
|
GetOCSPCertId(certid, id);
|
||
|
if(!OCSP_request_add0_id(req, OCSP_CERTID_dup(id)))
|
||
|
ossl_raise(eOCSPError, NULL);
|
||
|
|
||
|
return self;
|
||
|
}
|
||
|
|
||
|
static VALUE
|
||
|
ossl_ocspreq_get_certid(VALUE self)
|
||
|
{
|
||
|
OCSP_REQUEST *req;
|
||
|
OCSP_ONEREQ *one;
|
||
|
OCSP_CERTID *id;
|
||
|
VALUE ary, tmp;
|
||
|
int i, count;
|
||
|
|
||
|
GetOCSPReq(self, req);
|
||
|
count = OCSP_request_onereq_count(req);
|
||
|
ary = (count > 0) ? rb_ary_new() : Qnil;
|
||
|
for(i = 0; i < count; i++){
|
||
|
one = OCSP_request_onereq_get0(req, i);
|
||
|
if(!(id = OCSP_CERTID_dup(OCSP_onereq_get0_id(one))))
|
||
|
ossl_raise(eOCSPError, NULL);
|
||
|
WrapOCSPCertId(cOCSPCertId, tmp, id);
|
||
|
rb_ary_push(ary, tmp);
|
||
|
}
|
||
|
|
||
|
return ary;
|
||
|
}
|
||
|
|
||
|
static VALUE
|
||
|
ossl_ocspreq_sign(int argc, VALUE *argv, VALUE self)
|
||
|
{
|
||
|
VALUE signer_cert, signer_key, certs, flags;
|
||
|
OCSP_REQUEST *req;
|
||
|
X509 *signer;
|
||
|
EVP_PKEY *key;
|
||
|
STACK_OF(X509) *x509s;
|
||
|
unsigned long flg;
|
||
|
int ret, status = 0;
|
||
|
|
||
|
rb_scan_args(argc, argv, "22", &signer_cert, &signer_key, &certs, &flags);
|
||
|
GetOCSPReq(self, req);
|
||
|
signer = GetX509CertPtr(signer_cert);
|
||
|
key = GetPrivPKeyPtr(signer_key);
|
||
|
flg = NIL_P(flags) ? 0 : NUM2INT(flags);
|
||
|
if(NIL_P(certs)){
|
||
|
x509s = sk_X509_new_null();
|
||
|
flags |= OCSP_NOCERTS;
|
||
|
}
|
||
|
else x509s = ossl_protect_x509_ary2sk(certs, &status);
|
||
|
if(status){
|
||
|
sk_X509_pop_free(x509s, X509_free);
|
||
|
rb_jump_tag(status);
|
||
|
}
|
||
|
ret = OCSP_request_sign(req, signer, key, EVP_sha1(), x509s, flg);
|
||
|
sk_X509_pop_free(x509s, X509_free);
|
||
|
if(!ret) ossl_raise(eOCSPError, NULL);
|
||
|
|
||
|
return self;
|
||
|
}
|
||
|
|
||
|
static VALUE
|
||
|
ossl_ocspreq_verify(int argc, VALUE *argv, VALUE self)
|
||
|
{
|
||
|
VALUE certs, store, flags;
|
||
|
OCSP_REQUEST *req;
|
||
|
STACK_OF(X509) *x509s;
|
||
|
X509_STORE *x509st;
|
||
|
int flg, result;
|
||
|
|
||
|
rb_scan_args(argc, argv, "21", &certs, &store, &flags);
|
||
|
GetOCSPReq(self, req);
|
||
|
x509st = GetX509StorePtr(store);
|
||
|
flg = NIL_P(flags) ? 0 : INT2NUM(flags);
|
||
|
x509s = ossl_x509_ary2sk(certs);
|
||
|
result = OCSP_request_verify(req, x509s, x509st, flg);
|
||
|
sk_X509_pop_free(x509s, X509_free);
|
||
|
if(!result) rb_warn("%s", ERR_error_string(ERR_peek_error(), NULL));
|
||
|
|
||
|
return result ? Qtrue : Qfalse;
|
||
|
}
|
||
|
|
||
|
static VALUE
|
||
|
ossl_ocspreq_to_der(VALUE self)
|
||
|
{
|
||
|
OCSP_REQUEST *req;
|
||
|
BIO *bio;
|
||
|
VALUE str;
|
||
|
int status = 0;
|
||
|
|
||
|
GetOCSPReq(self, req);
|
||
|
if(!(bio = BIO_new(BIO_s_mem()))) rb_raise(eOCSPError, NULL);
|
||
|
i2d_OCSP_REQUEST_bio(bio, req);
|
||
|
str = ossl_protect_membio2str(bio, &status);
|
||
|
BIO_free(bio);
|
||
|
if(status) rb_jump_tag(status);
|
||
|
|
||
|
return str;
|
||
|
}
|
||
|
|
||
|
/*
|
||
|
* OCSP::Response
|
||
|
*/
|
||
|
static VALUE
|
||
|
ossl_ocspres_s_create(VALUE klass, VALUE status, VALUE basic_resp)
|
||
|
{
|
||
|
OCSP_BASICRESP *bs;
|
||
|
OCSP_RESPONSE *res;
|
||
|
VALUE obj;
|
||
|
|
||
|
if(NIL_P(basic_resp)) bs = NULL;
|
||
|
else GetOCSPBasicRes(basic_resp, bs); /* NO NEED TO DUP */
|
||
|
if(!(res = OCSP_response_create(NUM2INT(status), bs)))
|
||
|
ossl_raise(eOCSPError, NULL);
|
||
|
WrapOCSPRes(klass, obj, res);
|
||
|
|
||
|
return obj;
|
||
|
}
|
||
|
|
||
|
static VALUE
|
||
|
ossl_ocspres_alloc(VALUE klass)
|
||
|
{
|
||
|
OCSP_RESPONSE *res;
|
||
|
VALUE obj;
|
||
|
|
||
|
if(!(res = OCSP_RESPONSE_new()))
|
||
|
ossl_raise(eOCSPError, NULL);
|
||
|
WrapOCSPRes(klass, obj, res);
|
||
|
|
||
|
return obj;
|
||
|
}
|
||
|
DEFINE_ALLOC_WRAPPER(ossl_ocspreq_alloc)
|
||
|
|
||
|
static VALUE
|
||
|
ossl_ocspres_initialize(int argc, VALUE *argv, VALUE self)
|
||
|
{
|
||
|
VALUE arg;
|
||
|
BIO *bio;
|
||
|
|
||
|
rb_scan_args(argc, argv, "01", &arg);
|
||
|
bio = ossl_obj2bio(arg);
|
||
|
if(!d2i_OCSP_RESPONSE_bio(bio, (OCSP_RESPONSE**)&DATA_PTR(self))){
|
||
|
BIO_free(bio);
|
||
|
ossl_raise(eOCSPError, "cannot load DER encoded response");
|
||
|
}
|
||
|
BIO_free(bio);
|
||
|
|
||
|
return self;
|
||
|
}
|
||
|
|
||
|
static VALUE
|
||
|
ossl_ocspres_status(VALUE self)
|
||
|
{
|
||
|
OCSP_RESPONSE *res;
|
||
|
int st;
|
||
|
|
||
|
GetOCSPRes(self, res);
|
||
|
st = OCSP_response_status(res);
|
||
|
|
||
|
return INT2NUM(st);
|
||
|
}
|
||
|
|
||
|
static VALUE
|
||
|
ossl_ocspres_status_string(VALUE self)
|
||
|
{
|
||
|
OCSP_RESPONSE *res;
|
||
|
int st;
|
||
|
|
||
|
GetOCSPRes(self, res);
|
||
|
st = OCSP_response_status(res);
|
||
|
|
||
|
return rb_str_new2(OCSP_response_status_str(st));
|
||
|
}
|
||
|
|
||
|
static VALUE
|
||
|
ossl_ocspres_get_basic(VALUE self)
|
||
|
{
|
||
|
OCSP_RESPONSE *res;
|
||
|
OCSP_BASICRESP *bs;
|
||
|
VALUE ret;
|
||
|
|
||
|
GetOCSPRes(self, res);
|
||
|
if(!(bs = OCSP_response_get1_basic(res)))
|
||
|
return Qnil;
|
||
|
WrapOCSPBasicRes(cOCSPBasicRes, ret, bs);
|
||
|
|
||
|
return ret;
|
||
|
}
|
||
|
|
||
|
static VALUE
|
||
|
ossl_ocspres_to_der(VALUE self)
|
||
|
{
|
||
|
OCSP_RESPONSE *res;
|
||
|
BIO *bio;
|
||
|
VALUE str;
|
||
|
int status = 0;
|
||
|
|
||
|
GetOCSPRes(self, res);
|
||
|
if(!(bio = BIO_new(BIO_s_mem()))) rb_raise(eOCSPError, NULL);
|
||
|
i2d_OCSP_RESPONSE_bio(bio, res);
|
||
|
str = ossl_protect_membio2str(bio, &status);
|
||
|
BIO_free(bio);
|
||
|
if(status) rb_jump_tag(status);
|
||
|
|
||
|
return str;
|
||
|
}
|
||
|
|
||
|
/*
|
||
|
* OCSP::BasicResponse
|
||
|
*/
|
||
|
static VALUE
|
||
|
ossl_ocspbres_alloc(VALUE klass)
|
||
|
{
|
||
|
OCSP_BASICRESP *bs;
|
||
|
VALUE obj;
|
||
|
|
||
|
if(!(bs = OCSP_BASICRESP_new()))
|
||
|
ossl_raise(eOCSPError, NULL);
|
||
|
WrapOCSPBasicRes(klass, obj, bs);
|
||
|
|
||
|
return obj;
|
||
|
}
|
||
|
DEFINE_ALLOC_WRAPPER(ossl_ocspbres_alloc)
|
||
|
|
||
|
static VALUE
|
||
|
ossl_ocspbres_initialize(int argc, VALUE *argv, VALUE self)
|
||
|
{
|
||
|
return self;
|
||
|
}
|
||
|
|
||
|
static VALUE
|
||
|
ossl_ocspbres_copy_nonce(VALUE self, VALUE request)
|
||
|
{
|
||
|
OCSP_BASICRESP *bs;
|
||
|
OCSP_REQUEST *req;
|
||
|
int ret;
|
||
|
|
||
|
GetOCSPBasicRes(self, bs);
|
||
|
SafeGetOCSPReq(request, req);
|
||
|
ret = OCSP_copy_nonce(bs, req);
|
||
|
|
||
|
return INT2NUM(ret);
|
||
|
}
|
||
|
|
||
|
static VALUE
|
||
|
ossl_ocspbres_add_nonce(int argc, VALUE *argv, VALUE self)
|
||
|
{
|
||
|
OCSP_BASICRESP *bs;
|
||
|
VALUE val;
|
||
|
int ret;
|
||
|
|
||
|
GetOCSPBasicRes(self, bs);
|
||
|
rb_scan_args(argc, argv, "01", &val);
|
||
|
if(NIL_P(val))
|
||
|
ret = OCSP_basic_add1_nonce(bs, NULL, -1);
|
||
|
else{
|
||
|
StringValue(val);
|
||
|
ret = OCSP_basic_add1_nonce(bs, RSTRING(val)->ptr, RSTRING(val)->len);
|
||
|
}
|
||
|
if(!ret) ossl_raise(eOCSPError, NULL);
|
||
|
|
||
|
return self;
|
||
|
}
|
||
|
|
||
|
static VALUE
|
||
|
ossl_ocspbres_add_status(VALUE self, VALUE cid, VALUE status,
|
||
|
VALUE reason, VALUE revtime,
|
||
|
VALUE thisupd, VALUE nextupd, VALUE ext)
|
||
|
{
|
||
|
OCSP_BASICRESP *bs;
|
||
|
OCSP_SINGLERESP *single;
|
||
|
OCSP_CERTID *id;
|
||
|
int st, rsn;
|
||
|
ASN1_TIME *ths, *nxt, *rev;
|
||
|
int error, i, rstatus = 0;
|
||
|
VALUE tmp;
|
||
|
|
||
|
GetOCSPBasicRes(self, bs);
|
||
|
SafeGetOCSPCertId(cid, id);
|
||
|
st = NUM2INT(status);
|
||
|
rsn = NIL_P(status) ? 0 : NUM2INT(reason);
|
||
|
if(!NIL_P(ext)){
|
||
|
/* All ary's members should be X509Extension */
|
||
|
Check_Type(ext, T_ARRAY);
|
||
|
for (i = 0; i < RARRAY(ext)->len; i++)
|
||
|
OSSL_Check_Kind(RARRAY(ext)->ptr[i], cX509Ext);
|
||
|
}
|
||
|
|
||
|
error = 0;
|
||
|
ths = nxt = rev = NULL;
|
||
|
if(!NIL_P(revtime)){
|
||
|
tmp = rb_protect(rb_Integer, revtime, &rstatus);
|
||
|
if(rstatus) goto err;
|
||
|
rev = X509_gmtime_adj(NULL, NUM2INT(tmp));
|
||
|
}
|
||
|
tmp = rb_protect(rb_Integer, thisupd, &rstatus);
|
||
|
if(rstatus) goto err;
|
||
|
ths = X509_gmtime_adj(NULL, NUM2INT(tmp));
|
||
|
tmp = rb_protect(rb_Integer, nextupd, &rstatus);
|
||
|
if(rstatus) goto err;
|
||
|
nxt = X509_gmtime_adj(NULL, NUM2INT(tmp));
|
||
|
|
||
|
if(!(single = OCSP_basic_add1_status(bs, id, st, rsn, rev, ths, nxt))){
|
||
|
error = 1;
|
||
|
goto err;
|
||
|
}
|
||
|
|
||
|
if(!NIL_P(ext)){
|
||
|
X509_EXTENSION *x509ext;
|
||
|
sk_X509_EXTENSION_pop_free(single->singleExtensions, X509_EXTENSION_free);
|
||
|
single->singleExtensions = NULL;
|
||
|
for(i = 0; i < RARRAY(ext)->len; i++){
|
||
|
x509ext = DupX509ExtPtr(RARRAY(ext)->ptr[i]);
|
||
|
if(!OCSP_SINGLERESP_add_ext(single, x509ext, -1)){
|
||
|
X509_EXTENSION_free(x509ext);
|
||
|
error = 1;
|
||
|
goto err;
|
||
|
}
|
||
|
X509_EXTENSION_free(x509ext);
|
||
|
}
|
||
|
}
|
||
|
|
||
|
err:
|
||
|
ASN1_TIME_free(ths);
|
||
|
ASN1_TIME_free(nxt);
|
||
|
ASN1_TIME_free(rev);
|
||
|
if(error) ossl_raise(eOCSPError, NULL);
|
||
|
if(rstatus) rb_jump_tag(rstatus);
|
||
|
|
||
|
return self;
|
||
|
}
|
||
|
|
||
|
static VALUE
|
||
|
ossl_ocspbres_get_status(VALUE self)
|
||
|
{
|
||
|
OCSP_BASICRESP *bs;
|
||
|
OCSP_SINGLERESP *single;
|
||
|
OCSP_CERTID *cid;
|
||
|
ASN1_TIME *revtime, *thisupd, *nextupd;
|
||
|
int status, reason;
|
||
|
X509_EXTENSION *x509ext;
|
||
|
VALUE ret, ary, ext;
|
||
|
int count, ext_count, i, j;
|
||
|
|
||
|
GetOCSPBasicRes(self, bs);
|
||
|
ret = rb_ary_new();
|
||
|
count = OCSP_resp_count(bs);
|
||
|
for(i = 0; i < count; i++){
|
||
|
single = OCSP_resp_get0(bs, i);
|
||
|
if(!single) continue;
|
||
|
|
||
|
revtime = thisupd = nextupd = NULL;
|
||
|
status = OCSP_single_get0_status(single, &reason, &revtime,
|
||
|
&thisupd, &nextupd);
|
||
|
if(status < 0) continue;
|
||
|
if(!(cid = OCSP_CERTID_dup(single->certId)))
|
||
|
ossl_raise(eOCSPError, NULL);
|
||
|
ary = rb_ary_new();
|
||
|
rb_ary_push(ary, ossl_ocspcertid_new(cid));
|
||
|
rb_ary_push(ary, INT2NUM(status));
|
||
|
rb_ary_push(ary, INT2NUM(reason));
|
||
|
rb_ary_push(ary, revtime ? asn1time_to_time(revtime) : Qnil);
|
||
|
rb_ary_push(ary, thisupd ? asn1time_to_time(thisupd) : Qnil);
|
||
|
rb_ary_push(ary, nextupd ? asn1time_to_time(nextupd) : Qnil);
|
||
|
ext = rb_ary_new();
|
||
|
ext_count = OCSP_SINGLERESP_get_ext_count(single);
|
||
|
for(j = 0; j < ext_count; j++){
|
||
|
x509ext = OCSP_SINGLERESP_get_ext(single, j);
|
||
|
rb_ary_push(ext, ossl_x509ext_new(x509ext));
|
||
|
}
|
||
|
rb_ary_push(ary, ext);
|
||
|
rb_ary_push(ret, ary);
|
||
|
}
|
||
|
|
||
|
return ret;
|
||
|
}
|
||
|
|
||
|
static VALUE
|
||
|
ossl_ocspbres_sign(int argc, VALUE *argv, VALUE self)
|
||
|
{
|
||
|
VALUE signer_cert, signer_key, certs, flags;
|
||
|
OCSP_BASICRESP *bs;
|
||
|
X509 *signer;
|
||
|
EVP_PKEY *key;
|
||
|
STACK_OF(X509) *x509s;
|
||
|
unsigned long flg;
|
||
|
int ret, status = 0;
|
||
|
|
||
|
rb_scan_args(argc, argv, "22", &signer_cert, &signer_key, &certs, &flags);
|
||
|
GetOCSPBasicRes(self, bs);
|
||
|
signer = GetX509CertPtr(signer_cert);
|
||
|
key = GetPrivPKeyPtr(signer_key);
|
||
|
flg = NIL_P(flags) ? 0 : NUM2INT(flags);
|
||
|
if(NIL_P(certs)){
|
||
|
x509s = sk_X509_new_null();
|
||
|
flg |= OCSP_NOCERTS;
|
||
|
}
|
||
|
else{
|
||
|
x509s = ossl_protect_x509_ary2sk(certs, &status);
|
||
|
if(status) rb_jump_tag(status);
|
||
|
}
|
||
|
ret = OCSP_basic_sign(bs, signer, key, EVP_sha1(), x509s, flg);
|
||
|
sk_X509_pop_free(x509s, X509_free);
|
||
|
if(!ret) ossl_raise(eOCSPError, NULL);
|
||
|
|
||
|
return self;
|
||
|
}
|
||
|
|
||
|
static VALUE
|
||
|
ossl_ocspbres_verify(int argc, VALUE *argv, VALUE self)
|
||
|
{
|
||
|
VALUE certs, store, flags;
|
||
|
OCSP_BASICRESP *bs;
|
||
|
STACK_OF(X509) *x509s;
|
||
|
X509_STORE *x509st;
|
||
|
int flg, result;
|
||
|
|
||
|
rb_scan_args(argc, argv, "21", &certs, &store, &flags);
|
||
|
GetOCSPBasicRes(self, bs);
|
||
|
x509st = GetX509StorePtr(store);
|
||
|
flg = NIL_P(flags) ? 0 : INT2NUM(flags);
|
||
|
x509s = ossl_x509_ary2sk(certs);
|
||
|
result = OCSP_basic_verify(bs, x509s, x509st, flg);
|
||
|
sk_X509_pop_free(x509s, X509_free);
|
||
|
if(!result) rb_warn("%s", ERR_error_string(ERR_peek_error(), NULL));
|
||
|
|
||
|
return result ? Qtrue : Qfalse;
|
||
|
}
|
||
|
|
||
|
/*
|
||
|
* OCSP::CertificateId
|
||
|
*/
|
||
|
static VALUE
|
||
|
ossl_ocspcid_alloc(VALUE klass)
|
||
|
{
|
||
|
OCSP_CERTID *id;
|
||
|
VALUE obj;
|
||
|
|
||
|
if(!(id = OCSP_CERTID_new()))
|
||
|
ossl_raise(eOCSPError, NULL);
|
||
|
WrapOCSPCertId(klass, obj, id);
|
||
|
|
||
|
return obj;
|
||
|
}
|
||
|
DEFINE_ALLOC_WRAPPER(ossl_ocspcid_alloc)
|
||
|
|
||
|
static VALUE
|
||
|
ossl_ocspcid_initialize(VALUE self, VALUE subject, VALUE issuer)
|
||
|
{
|
||
|
OCSP_CERTID *id, *newid;
|
||
|
X509 *x509s, *x509i;
|
||
|
|
||
|
GetOCSPCertId(self, id);
|
||
|
x509s = GetX509CertPtr(subject); /* NO NEED TO DUP */
|
||
|
x509i = GetX509CertPtr(issuer); /* NO NEED TO DUP */
|
||
|
if(!(newid = OCSP_cert_to_id(NULL, x509s, x509i)))
|
||
|
ossl_raise(eOCSPError, NULL);
|
||
|
OCSP_CERTID_free(id);
|
||
|
RDATA(self)->data = newid;
|
||
|
|
||
|
return self;
|
||
|
}
|
||
|
|
||
|
static VALUE
|
||
|
ossl_ocspcid_cmp(VALUE self, VALUE other)
|
||
|
{
|
||
|
OCSP_CERTID *id, *id2;
|
||
|
int result;
|
||
|
|
||
|
GetOCSPCertId(self, id);
|
||
|
SafeGetOCSPCertId(other, id2);
|
||
|
result = OCSP_id_cmp(id, id2);
|
||
|
|
||
|
return (result == 0) ? Qtrue : Qfalse;
|
||
|
}
|
||
|
|
||
|
static VALUE
|
||
|
ossl_ocspcid_cmp_issuer(VALUE self, VALUE other)
|
||
|
{
|
||
|
OCSP_CERTID *id, *id2;
|
||
|
int result;
|
||
|
|
||
|
GetOCSPCertId(self, id);
|
||
|
SafeGetOCSPCertId(other, id2);
|
||
|
result = OCSP_id_issuer_cmp(id, id2);
|
||
|
|
||
|
return (result == 0) ? Qtrue : Qfalse;
|
||
|
}
|
||
|
|
||
|
static VALUE
|
||
|
ossl_ocspcid_get_serial(VALUE self)
|
||
|
{
|
||
|
OCSP_CERTID *id;
|
||
|
|
||
|
GetOCSPCertId(self, id);
|
||
|
|
||
|
return asn1integer_to_num(id->serialNumber);
|
||
|
}
|
||
|
|
||
|
void
|
||
|
Init_ossl_ocsp()
|
||
|
{
|
||
|
mOCSP = rb_define_module_under(mOSSL, "OCSP");
|
||
|
|
||
|
eOCSPError = rb_define_class_under(mOCSP, "OCSPError", rb_cObject);
|
||
|
|
||
|
cOCSPReq = rb_define_class_under(mOCSP, "Request", rb_cObject);
|
||
|
rb_define_alloc_func(cOCSPReq, ossl_ocspreq_alloc);
|
||
|
rb_define_method(cOCSPReq, "initialize", ossl_ocspreq_initialize, -1);
|
||
|
rb_define_method(cOCSPReq, "add_nonce", ossl_ocspreq_add_nonce, -1);
|
||
|
rb_define_method(cOCSPReq, "check_nonce", ossl_ocspreq_check_nonce, 1);
|
||
|
rb_define_method(cOCSPReq, "add_certid", ossl_ocspreq_add_certid, 1);
|
||
|
rb_define_method(cOCSPReq, "certid", ossl_ocspreq_get_certid, 0);
|
||
|
rb_define_method(cOCSPReq, "sign", ossl_ocspreq_sign, -1);
|
||
|
rb_define_method(cOCSPReq, "verify", ossl_ocspreq_verify, -1);
|
||
|
rb_define_method(cOCSPReq, "to_der", ossl_ocspreq_to_der, 0);
|
||
|
|
||
|
cOCSPRes = rb_define_class_under(mOCSP, "Response", rb_cObject);
|
||
|
rb_define_singleton_method(cOCSPRes, "create", ossl_ocspres_s_create, 2);
|
||
|
rb_define_alloc_func(cOCSPRes, ossl_ocspres_alloc);
|
||
|
rb_define_method(cOCSPRes, "initialize", ossl_ocspres_initialize, -1);
|
||
|
rb_define_method(cOCSPRes, "status", ossl_ocspres_status, 0);
|
||
|
rb_define_method(cOCSPRes, "status_string", ossl_ocspres_status_string, 0);
|
||
|
rb_define_method(cOCSPRes, "basic", ossl_ocspres_get_basic, 0);
|
||
|
rb_define_method(cOCSPRes, "to_der", ossl_ocspres_to_der, 0);
|
||
|
|
||
|
cOCSPBasicRes = rb_define_class_under(mOCSP, "BasicResponse", rb_cObject);
|
||
|
rb_define_alloc_func(cOCSPBasicRes, ossl_ocspbres_alloc);
|
||
|
rb_define_method(cOCSPBasicRes, "initialize", ossl_ocspbres_initialize, -1);
|
||
|
rb_define_method(cOCSPBasicRes, "copy_nonce", ossl_ocspbres_copy_nonce, 1);
|
||
|
rb_define_method(cOCSPBasicRes, "add_nonce", ossl_ocspbres_add_nonce, -1);
|
||
|
rb_define_method(cOCSPBasicRes, "add_status", ossl_ocspbres_add_status, 7);
|
||
|
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);
|
||
|
|
||
|
cOCSPCertId = rb_define_class_under(mOCSP, "CertificateId", rb_cObject);
|
||
|
rb_define_alloc_func(cOCSPCertId, ossl_ocspcid_alloc);
|
||
|
rb_define_method(cOCSPCertId, "initialize", ossl_ocspcid_initialize, 2);
|
||
|
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);
|
||
|
|
||
|
#define DefOCSPConst(x) rb_define_const(mOCSP, #x, INT2NUM(OCSP_##x))
|
||
|
|
||
|
DefOCSPConst(RESPONSE_STATUS_SUCCESSFUL);
|
||
|
DefOCSPConst(RESPONSE_STATUS_MALFORMEDREQUEST);
|
||
|
DefOCSPConst(RESPONSE_STATUS_INTERNALERROR);
|
||
|
DefOCSPConst(RESPONSE_STATUS_TRYLATER);
|
||
|
DefOCSPConst(RESPONSE_STATUS_SIGREQUIRED);
|
||
|
DefOCSPConst(RESPONSE_STATUS_UNAUTHORIZED);
|
||
|
|
||
|
DefOCSPConst(REVOKED_STATUS_NOSTATUS);
|
||
|
DefOCSPConst(REVOKED_STATUS_UNSPECIFIED);
|
||
|
DefOCSPConst(REVOKED_STATUS_KEYCOMPROMISE);
|
||
|
DefOCSPConst(REVOKED_STATUS_CACOMPROMISE);
|
||
|
DefOCSPConst(REVOKED_STATUS_AFFILIATIONCHANGED);
|
||
|
DefOCSPConst(REVOKED_STATUS_SUPERSEDED);
|
||
|
DefOCSPConst(REVOKED_STATUS_CESSATIONOFOPERATION);
|
||
|
DefOCSPConst(REVOKED_STATUS_CERTIFICATEHOLD);
|
||
|
DefOCSPConst(REVOKED_STATUS_REMOVEFROMCRL);
|
||
|
|
||
|
DefOCSPConst(NOCERTS);
|
||
|
DefOCSPConst(NOINTERN);
|
||
|
DefOCSPConst(NOSIGS);
|
||
|
DefOCSPConst(NOCHAIN);
|
||
|
DefOCSPConst(NOVERIFY);
|
||
|
DefOCSPConst(NOEXPLICIT);
|
||
|
DefOCSPConst(NOCASIGN);
|
||
|
DefOCSPConst(NODELEGATED);
|
||
|
DefOCSPConst(NOCHECKS);
|
||
|
DefOCSPConst(TRUSTOTHER);
|
||
|
DefOCSPConst(RESPID_KEY);
|
||
|
DefOCSPConst(NOTIME);
|
||
|
|
||
|
#define DefOCSPVConst(x) rb_define_const(mOCSP, "V_" #x, INT2NUM(V_OCSP_##x))
|
||
|
|
||
|
DefOCSPVConst(CERTSTATUS_GOOD);
|
||
|
DefOCSPVConst(CERTSTATUS_REVOKED);
|
||
|
DefOCSPVConst(CERTSTATUS_UNKNOWN);
|
||
|
DefOCSPVConst(RESPID_NAME);
|
||
|
DefOCSPVConst(RESPID_KEY);
|
||
|
}
|
||
|
|
||
|
#else /* ! OSSL_OCSP_ENABLED */
|
||
|
void
|
||
|
Init_ossl_ocsp()
|
||
|
{
|
||
|
}
|
||
|
#endif
|