From a05e89ca65c24dd4821e34172c891e5b8de33a54 Mon Sep 17 00:00:00 2001 From: technorama Date: Mon, 2 Apr 2007 22:10:12 +0000 Subject: * ext/openssl/ossl_{ssl.[ch],ssl_session.c}}, ext/openssl/lib/openssl/lib/openssl/ssl.rb: New SSL::Session class. Add session cb's, getter/setters, config, and statistics methods. git-svn-id: svn+ssh://ci.ruby-lang.org/ruby/trunk@12134 b2dd03c8-39d4-4d8f-98ff-823fe69b080e --- ext/openssl/ossl_ssl_session.c | 292 +++++++++++++++++++++++++++++++++++++++++ 1 file changed, 292 insertions(+) create mode 100644 ext/openssl/ossl_ssl_session.c (limited to 'ext/openssl/ossl_ssl_session.c') diff --git a/ext/openssl/ossl_ssl_session.c b/ext/openssl/ossl_ssl_session.c new file mode 100644 index 0000000000..efc49395a0 --- /dev/null +++ b/ext/openssl/ossl_ssl_session.c @@ -0,0 +1,292 @@ +/* + * Copyright (C) 2004-2007 Technorama Ltd. + */ + +#include "ossl.h" + +#define GetSSLSession(obj, sess) do { \ + Data_Get_Struct(obj, SSL_SESSION, sess); \ + if (!sess) { \ + ossl_raise(rb_eRuntimeError, "SSL Session wasn't initialized."); \ + } \ +} while (0) + +#define SafeGetSSLSession(obj, sess) do { \ + OSSL_Check_Kind(obj, cSSLSession); \ + GetSSLSession(obj, sess); \ +} while (0) + + +VALUE cSSLSession; +static VALUE eSSLSession; + +static VALUE ossl_ssl_session_alloc(VALUE klass) +{ + Data_Wrap_Struct(klass, 0, SSL_SESSION_free, NULL); +} + +/* + * call-seq: + * Session.new(SSLSocket | string) => session + * + * === Parameters + * +SSLSocket+ is an OpenSSL::SSL::SSLSocket + * +string+ must be a DER or PEM encoded Session. +*/ +static VALUE ossl_ssl_session_initialize(VALUE self, VALUE arg1) +{ + SSL_SESSION *ctx = NULL; + VALUE obj; + unsigned char *p; + + if (RDATA(self)->data) + ossl_raise(eSSLSession, "SSL Session already initialized"); + + if (rb_obj_is_instance_of(arg1, cSSLSocket)) { + SSL *ssl; + + Data_Get_Struct(arg1, SSL, ssl); + + if ((ctx = SSL_get1_session(ssl)) == NULL) + ossl_raise(eSSLSession, "no session available"); + } else { + BIO *in = ossl_obj2bio(arg1); + + ctx = PEM_read_bio_SSL_SESSION(in, NULL, NULL, NULL); + + if (!ctx) { + BIO_reset(in); + ctx = d2i_SSL_SESSION_bio(in, NULL); + } + + BIO_free(in); + + if (!ctx) + ossl_raise(rb_eArgError, "unknown type"); + } + + /* should not happen */ + if (ctx == NULL) + ossl_raise(eSSLSession, "ctx not set - internal error"); + + RDATA(self)->data = ctx; + + return self; +} + +/* + * call-seq: + * session1 == session2 -> boolean + * +*/ +static VALUE ossl_ssl_session_eq(VALUE val1, VALUE val2) +{ + SSL_SESSION *ctx1, *ctx2; + + GetSSLSession(val1, ctx1); + SafeGetSSLSession(val2, ctx2); + + switch (SSL_SESSION_cmp(ctx1, ctx2)) { + case 0: return Qtrue; + default: return Qfalse; + } +} + +/* + * call-seq: + * session.time -> Time + * +*/ +static VALUE ossl_ssl_session_get_time(VALUE self) +{ + SSL_SESSION *ctx; + time_t t; + + GetSSLSession(self, ctx); + + t = SSL_SESSION_get_time(ctx); + + if (t == 0) + return Qnil; + + return rb_funcall(rb_cTime, rb_intern("at"), 1, LONG2NUM(t)); +} + +/* + * call-seq: + * session.timeout -> integer + * + * How long until the session expires in seconds. + * +*/ +static VALUE ossl_ssl_session_get_timeout(VALUE self) +{ + SSL_SESSION *ctx; + time_t t; + + GetSSLSession(self, ctx); + + t = SSL_SESSION_get_timeout(ctx); + + return ULONG2NUM(t); +} + +#define SSLSESSION_SET_TIME(func) \ + static VALUE ossl_ssl_session_set_##func(VALUE self, VALUE time_v) \ + { \ + SSL_SESSION *ctx; \ + time_t t; \ + \ + GetSSLSession(self, ctx); \ + \ + if (rb_obj_is_instance_of(time_v, rb_cTime)) { \ + time_v = rb_funcall(time_v, rb_intern("to_i"), 0); \ + } else if (FIXNUM_P(time_v)) { \ + ; \ + } else { \ + rb_raise(rb_eArgError, "unknown type"); \ + } \ + \ + t = NUM2ULONG(time_v); \ + \ + SSL_SESSION_set_##func(ctx, t); \ + \ + return ossl_ssl_session_get_##func(self); \ + } + +SSLSESSION_SET_TIME(time) +SSLSESSION_SET_TIME(timeout) + +/* + * call-seq: + * session.id -> aString + * + * Returns the Session ID. +*/ +static VALUE ossl_ssl_session_get_id(VALUE self) +{ + SSL_SESSION *ctx; + const unsigned char *p = NULL; + unsigned int i = 0; + + GetSSLSession(self, ctx); + + p = SSL_SESSION_get_id(ctx, &i); + + return rb_str_new(p, i); +} + +/* + * call-seq: + * session.to_der -> aString + * + * Returns an ASN1 encoded String that contains the Session object. +*/ +static VALUE ossl_ssl_session_to_der(VALUE self) +{ + SSL_SESSION *ctx; + unsigned char buf[1024*10], *p; + int len; + + GetSSLSession(self, ctx); + + p = buf; + len = i2d_SSL_SESSION(ctx, &p); + + if (len <= 0) + ossl_raise(eSSLSession, "i2d_SSL_SESSION"); + else if (len >= sizeof(buf)) + ossl_raise(eSSLSession, "i2d_SSL_SESSION too large"); + + return rb_str_new(p, len); +} + +/* + * call-seq: + * session.to_pem -> String + * + * Returns a PEM encoded String that contains the Session object. +*/ +static VALUE ossl_ssl_session_to_pem(VALUE self) +{ + SSL_SESSION *ctx; + BIO *out; + BUF_MEM *buf; + VALUE str; + int i; + + GetSSLSession(self, ctx); + + if (!(out = BIO_new(BIO_s_mem()))) { + ossl_raise(eSSLSession, "BIO_s_mem()"); + } + + if (!(i=PEM_write_bio_SSL_SESSION(out, ctx))) { + BIO_free(out); + ossl_raise(eSSLSession, "SSL_SESSION_print()"); + } + + BIO_get_mem_ptr(out, &buf); + str = rb_str_new(buf->data, buf->length); + BIO_free(out); + + return str; +} + + +/* + * call-seq: + * session.to_text -> String + * + * Shows everything in the Session object. +*/ +static VALUE ossl_ssl_session_to_text(VALUE self) +{ + SSL_SESSION *ctx; + BIO *out; + BUF_MEM *buf; + VALUE str; + + GetSSLSession(self, ctx); + + if (!(out = BIO_new(BIO_s_mem()))) { + ossl_raise(eSSLSession, "BIO_s_mem()"); + } + + if (!SSL_SESSION_print(out, ctx)) { + BIO_free(out); + ossl_raise(eSSLSession, "SSL_SESSION_print()"); + } + + BIO_get_mem_ptr(out, &buf); + str = rb_str_new(buf->data, buf->length); + BIO_free(out); + + return str; +} + + +void Init_ossl_ssl_session(void) +{ +#if 0 /* let rdoc know about mOSSL */ + mOSSL = rb_define_module("OpenSSL"); + mSSL = rb_define_module_under(mOSSL, "SSL"); +#endif + cSSLSession = rb_define_class_under(mSSL, "Session", rb_cObject); + eSSLSession = rb_define_class_under(cSSLSession, "SessionError", eOSSLError); + + rb_define_alloc_func(cSSLSession, ossl_ssl_session_alloc); + rb_define_method(cSSLSession, "initialize", ossl_ssl_session_initialize, 1); + + rb_define_method(cSSLSession, "==", ossl_ssl_session_eq, 1); + + rb_define_method(cSSLSession, "time", ossl_ssl_session_get_time, 0); + rb_define_method(cSSLSession, "time=", ossl_ssl_session_set_time, 1); + rb_define_method(cSSLSession, "timeout", ossl_ssl_session_get_timeout, 0); + rb_define_method(cSSLSession, "timeout=", ossl_ssl_session_set_timeout, 1); + + rb_define_method(cSSLSession, "id", ossl_ssl_session_get_id, 0); + rb_define_method(cSSLSession, "to_der", ossl_ssl_session_to_der, 0); + rb_define_method(cSSLSession, "to_pem", ossl_ssl_session_to_pem, 0); + rb_define_method(cSSLSession, "to_text", ossl_ssl_session_to_text, 0); +} -- cgit v1.2.3