00001
00002
00003
00004
00005
00006
00007
00008
00009
00010
00011 #include "ossl.h"
00012
00013 #if defined(HAVE_SYS_TIME_H)
00014 # include <sys/time.h>
00015 #elif !defined(NT) && !defined(_WIN32)
00016 struct timeval {
00017 long tv_sec;
00018 long tv_usec;
00019 };
00020 #endif
00021
00022
00023
00024
00025 VALUE
00026 asn1time_to_time(ASN1_TIME *time)
00027 {
00028 struct tm tm;
00029 VALUE argv[6];
00030
00031 if (!time || !time->data) return Qnil;
00032 memset(&tm, 0, sizeof(struct tm));
00033
00034 switch (time->type) {
00035 case V_ASN1_UTCTIME:
00036 if (sscanf((const char *)time->data, "%2d%2d%2d%2d%2d%2dZ", &tm.tm_year, &tm.tm_mon,
00037 &tm.tm_mday, &tm.tm_hour, &tm.tm_min, &tm.tm_sec) != 6) {
00038 ossl_raise(rb_eTypeError, "bad UTCTIME format");
00039 }
00040 if (tm.tm_year < 69) {
00041 tm.tm_year += 2000;
00042 } else {
00043 tm.tm_year += 1900;
00044 }
00045 break;
00046 case V_ASN1_GENERALIZEDTIME:
00047 if (sscanf((const char *)time->data, "%4d%2d%2d%2d%2d%2dZ", &tm.tm_year, &tm.tm_mon,
00048 &tm.tm_mday, &tm.tm_hour, &tm.tm_min, &tm.tm_sec) != 6) {
00049 ossl_raise(rb_eTypeError, "bad GENERALIZEDTIME format" );
00050 }
00051 break;
00052 default:
00053 rb_warning("unknown time format");
00054 return Qnil;
00055 }
00056 argv[0] = INT2NUM(tm.tm_year);
00057 argv[1] = INT2NUM(tm.tm_mon);
00058 argv[2] = INT2NUM(tm.tm_mday);
00059 argv[3] = INT2NUM(tm.tm_hour);
00060 argv[4] = INT2NUM(tm.tm_min);
00061 argv[5] = INT2NUM(tm.tm_sec);
00062
00063 return rb_funcall2(rb_cTime, rb_intern("utc"), 6, argv);
00064 }
00065
00066
00067
00068
00069 extern struct timeval rb_time_timeval(VALUE);
00070
00071 time_t
00072 time_to_time_t(VALUE time)
00073 {
00074 return (time_t)NUM2LONG(rb_Integer(time));
00075 }
00076
00077
00078
00079
00080 VALUE
00081 asn1str_to_str(ASN1_STRING *str)
00082 {
00083 return rb_str_new((const char *)str->data, str->length);
00084 }
00085
00086
00087
00088
00089
00090 #define DO_IT_VIA_RUBY 0
00091 VALUE
00092 asn1integer_to_num(ASN1_INTEGER *ai)
00093 {
00094 BIGNUM *bn;
00095 #if DO_IT_VIA_RUBY
00096 char *txt;
00097 #endif
00098 VALUE num;
00099
00100 if (!ai) {
00101 ossl_raise(rb_eTypeError, "ASN1_INTEGER is NULL!");
00102 }
00103 if (!(bn = ASN1_INTEGER_to_BN(ai, NULL))) {
00104 ossl_raise(eOSSLError, NULL);
00105 }
00106 #if DO_IT_VIA_RUBY
00107 if (!(txt = BN_bn2dec(bn))) {
00108 BN_free(bn);
00109 ossl_raise(eOSSLError, NULL);
00110 }
00111 num = rb_cstr_to_inum(txt, 10, Qtrue);
00112 OPENSSL_free(txt);
00113 #else
00114 num = ossl_bn_new(bn);
00115 #endif
00116 BN_free(bn);
00117
00118 return num;
00119 }
00120
00121 #if DO_IT_VIA_RUBY
00122 ASN1_INTEGER *
00123 num_to_asn1integer(VALUE obj, ASN1_INTEGER *ai)
00124 {
00125 BIGNUM *bn = NULL;
00126
00127 if (RTEST(rb_obj_is_kind_of(obj, cBN))) {
00128 bn = GetBNPtr(obj);
00129 } else {
00130 obj = rb_String(obj);
00131 if (!BN_dec2bn(&bn, StringValuePtr(obj))) {
00132 ossl_raise(eOSSLError, NULL);
00133 }
00134 }
00135 if (!(ai = BN_to_ASN1_INTEGER(bn, ai))) {
00136 BN_free(bn);
00137 ossl_raise(eOSSLError, NULL);
00138 }
00139 BN_free(bn);
00140 return ai;
00141 }
00142 #else
00143 ASN1_INTEGER *
00144 num_to_asn1integer(VALUE obj, ASN1_INTEGER *ai)
00145 {
00146 BIGNUM *bn = GetBNPtr(obj);
00147
00148 if (!(ai = BN_to_ASN1_INTEGER(bn, ai))) {
00149 ossl_raise(eOSSLError, NULL);
00150 }
00151 return ai;
00152 }
00153 #endif
00154
00155
00156
00157
00158
00159 #define ossl_asn1_get_value(o) rb_attr_get((o),rb_intern("@value"))
00160 #define ossl_asn1_get_tag(o) rb_attr_get((o),rb_intern("@tag"))
00161 #define ossl_asn1_get_tagging(o) rb_attr_get((o),rb_intern("@tagging"))
00162 #define ossl_asn1_get_tag_class(o) rb_attr_get((o),rb_intern("@tag_class"))
00163
00164 #define ossl_asn1_set_value(o,v) rb_iv_set((o),"@value",(v))
00165 #define ossl_asn1_set_tag(o,v) rb_iv_set((o),"@tag",(v))
00166 #define ossl_asn1_set_tagging(o,v) rb_iv_set((o),"@tagging",(v))
00167 #define ossl_asn1_set_tag_class(o,v) rb_iv_set((o),"@tag_class",(v))
00168
00169 VALUE mASN1;
00170 VALUE eASN1Error;
00171
00172 VALUE cASN1Data;
00173 VALUE cASN1Primitive;
00174 VALUE cASN1Constructive;
00175
00176 VALUE cASN1Boolean;
00177 VALUE cASN1Integer, cASN1Enumerated;
00178 VALUE cASN1BitString;
00179 VALUE cASN1OctetString, cASN1UTF8String;
00180 VALUE cASN1NumericString, cASN1PrintableString;
00181 VALUE cASN1T61String, cASN1VideotexString;
00182 VALUE cASN1IA5String, cASN1GraphicString;
00183 VALUE cASN1ISO64String, cASN1GeneralString;
00184 VALUE cASN1UniversalString, cASN1BMPString;
00185 VALUE cASN1Null;
00186 VALUE cASN1ObjectId;
00187 VALUE cASN1UTCTime, cASN1GeneralizedTime;
00188 VALUE cASN1Sequence, cASN1Set;
00189
00190 static ID sIMPLICIT, sEXPLICIT;
00191 static ID sUNIVERSAL, sAPPLICATION, sCONTEXT_SPECIFIC, sPRIVATE;
00192
00193
00194
00195
00196 static ASN1_BOOLEAN
00197 obj_to_asn1bool(VALUE obj)
00198 {
00199 #if OPENSSL_VERSION_NUMBER < 0x00907000L
00200 return RTEST(obj) ? 0xff : 0x100;
00201 #else
00202 return RTEST(obj) ? 0xff : 0x0;
00203 #endif
00204 }
00205
00206 static ASN1_INTEGER*
00207 obj_to_asn1int(VALUE obj)
00208 {
00209 return num_to_asn1integer(obj, NULL);
00210 }
00211
00212 static ASN1_BIT_STRING*
00213 obj_to_asn1bstr(VALUE obj, long unused_bits)
00214 {
00215 ASN1_BIT_STRING *bstr;
00216
00217 if(unused_bits < 0) unused_bits = 0;
00218 StringValue(obj);
00219 if(!(bstr = ASN1_BIT_STRING_new()))
00220 ossl_raise(eASN1Error, NULL);
00221 ASN1_BIT_STRING_set(bstr, (unsigned char *)RSTRING_PTR(obj), RSTRING_LEN(obj));
00222 bstr->flags &= ~(ASN1_STRING_FLAG_BITS_LEFT|0x07);
00223 bstr->flags |= ASN1_STRING_FLAG_BITS_LEFT|(unused_bits&0x07);
00224
00225 return bstr;
00226 }
00227
00228 static ASN1_STRING*
00229 obj_to_asn1str(VALUE obj)
00230 {
00231 ASN1_STRING *str;
00232
00233 StringValue(obj);
00234 if(!(str = ASN1_STRING_new()))
00235 ossl_raise(eASN1Error, NULL);
00236 ASN1_STRING_set(str, RSTRING_PTR(obj), RSTRING_LEN(obj));
00237
00238 return str;
00239 }
00240
00241 static ASN1_NULL*
00242 obj_to_asn1null(VALUE obj)
00243 {
00244 ASN1_NULL *null;
00245
00246 if(!NIL_P(obj))
00247 ossl_raise(eASN1Error, "nil expected");
00248 if(!(null = ASN1_NULL_new()))
00249 ossl_raise(eASN1Error, NULL);
00250
00251 return null;
00252 }
00253
00254 static ASN1_OBJECT*
00255 obj_to_asn1obj(VALUE obj)
00256 {
00257 ASN1_OBJECT *a1obj;
00258
00259 StringValue(obj);
00260 a1obj = OBJ_txt2obj(RSTRING_PTR(obj), 0);
00261 if(!a1obj) a1obj = OBJ_txt2obj(RSTRING_PTR(obj), 1);
00262 if(!a1obj) ossl_raise(eASN1Error, "invalid OBJECT ID");
00263
00264 return a1obj;
00265 }
00266
00267 static ASN1_UTCTIME*
00268 obj_to_asn1utime(VALUE time)
00269 {
00270 time_t sec;
00271 ASN1_UTCTIME *t;
00272
00273 sec = time_to_time_t(time);
00274 if(!(t = ASN1_UTCTIME_set(NULL, sec)))
00275 ossl_raise(eASN1Error, NULL);
00276
00277 return t;
00278 }
00279
00280 static ASN1_GENERALIZEDTIME*
00281 obj_to_asn1gtime(VALUE time)
00282 {
00283 time_t sec;
00284 ASN1_GENERALIZEDTIME *t;
00285
00286 sec = time_to_time_t(time);
00287 if(!(t =ASN1_GENERALIZEDTIME_set(NULL, sec)))
00288 ossl_raise(eASN1Error, NULL);
00289
00290 return t;
00291 }
00292
00293 static ASN1_STRING*
00294 obj_to_asn1derstr(VALUE obj)
00295 {
00296 ASN1_STRING *a1str;
00297 VALUE str;
00298
00299 str = ossl_to_der(obj);
00300 if(!(a1str = ASN1_STRING_new()))
00301 ossl_raise(eASN1Error, NULL);
00302 ASN1_STRING_set(a1str, RSTRING_PTR(str), RSTRING_LEN(str));
00303
00304 return a1str;
00305 }
00306
00307
00308
00309
00310 static VALUE
00311 decode_bool(unsigned char* der, int length)
00312 {
00313 int val;
00314 const unsigned char *p;
00315
00316 p = der;
00317 if((val = d2i_ASN1_BOOLEAN(NULL, &p, length)) < 0)
00318 ossl_raise(eASN1Error, NULL);
00319
00320 return val ? Qtrue : Qfalse;
00321 }
00322
00323 static VALUE
00324 decode_int(unsigned char* der, int length)
00325 {
00326 ASN1_INTEGER *ai;
00327 const unsigned char *p;
00328 VALUE ret;
00329 int status = 0;
00330
00331 p = der;
00332 if(!(ai = d2i_ASN1_INTEGER(NULL, &p, length)))
00333 ossl_raise(eASN1Error, NULL);
00334 ret = rb_protect((VALUE(*)_((VALUE)))asn1integer_to_num,
00335 (VALUE)ai, &status);
00336 ASN1_INTEGER_free(ai);
00337 if(status) rb_jump_tag(status);
00338
00339 return ret;
00340 }
00341
00342 static VALUE
00343 decode_bstr(unsigned char* der, int length, long *unused_bits)
00344 {
00345 ASN1_BIT_STRING *bstr;
00346 const unsigned char *p;
00347 long len;
00348 VALUE ret;
00349
00350 p = der;
00351 if(!(bstr = d2i_ASN1_BIT_STRING(NULL, &p, length)))
00352 ossl_raise(eASN1Error, NULL);
00353 len = bstr->length;
00354 *unused_bits = 0;
00355 if(bstr->flags & ASN1_STRING_FLAG_BITS_LEFT)
00356 *unused_bits = bstr->flags & 0x07;
00357 ret = rb_str_new((const char *)bstr->data, len);
00358 ASN1_BIT_STRING_free(bstr);
00359
00360 return ret;
00361 }
00362
00363 static VALUE
00364 decode_enum(unsigned char* der, int length)
00365 {
00366 ASN1_ENUMERATED *ai;
00367 const unsigned char *p;
00368 VALUE ret;
00369 int status = 0;
00370
00371 p = der;
00372 if(!(ai = d2i_ASN1_ENUMERATED(NULL, &p, length)))
00373 ossl_raise(eASN1Error, NULL);
00374 ret = rb_protect((VALUE(*)_((VALUE)))asn1integer_to_num,
00375 (VALUE)ai, &status);
00376 ASN1_ENUMERATED_free(ai);
00377 if(status) rb_jump_tag(status);
00378
00379 return ret;
00380 }
00381
00382 static VALUE
00383 decode_null(unsigned char* der, int length)
00384 {
00385 ASN1_NULL *null;
00386 const unsigned char *p;
00387
00388 p = der;
00389 if(!(null = d2i_ASN1_NULL(NULL, &p, length)))
00390 ossl_raise(eASN1Error, NULL);
00391 ASN1_NULL_free(null);
00392
00393 return Qnil;
00394 }
00395
00396 static VALUE
00397 decode_obj(unsigned char* der, int length)
00398 {
00399 ASN1_OBJECT *obj;
00400 const unsigned char *p;
00401 VALUE ret;
00402 int nid;
00403 BIO *bio;
00404
00405 p = der;
00406 if(!(obj = d2i_ASN1_OBJECT(NULL, &p, length)))
00407 ossl_raise(eASN1Error, NULL);
00408 if((nid = OBJ_obj2nid(obj)) != NID_undef){
00409 ASN1_OBJECT_free(obj);
00410 ret = rb_str_new2(OBJ_nid2sn(nid));
00411 }
00412 else{
00413 if(!(bio = BIO_new(BIO_s_mem()))){
00414 ASN1_OBJECT_free(obj);
00415 ossl_raise(eASN1Error, NULL);
00416 }
00417 i2a_ASN1_OBJECT(bio, obj);
00418 ASN1_OBJECT_free(obj);
00419 ret = ossl_membio2str(bio);
00420 }
00421
00422 return ret;
00423 }
00424
00425 static VALUE
00426 decode_time(unsigned char* der, int length)
00427 {
00428 ASN1_TIME *time;
00429 const unsigned char *p;
00430 VALUE ret;
00431 int status = 0;
00432
00433 p = der;
00434 if(!(time = d2i_ASN1_TIME(NULL, &p, length)))
00435 ossl_raise(eASN1Error, NULL);
00436 ret = rb_protect((VALUE(*)_((VALUE)))asn1time_to_time,
00437 (VALUE)time, &status);
00438 ASN1_TIME_free(time);
00439 if(status) rb_jump_tag(status);
00440
00441 return ret;
00442 }
00443
00444
00445
00446 typedef struct {
00447 const char *name;
00448 VALUE *klass;
00449 } ossl_asn1_info_t;
00450
00451 static ossl_asn1_info_t ossl_asn1_info[] = {
00452 { "EOC", NULL, },
00453 { "BOOLEAN", &cASN1Boolean, },
00454 { "INTEGER", &cASN1Integer, },
00455 { "BIT_STRING", &cASN1BitString, },
00456 { "OCTET_STRING", &cASN1OctetString, },
00457 { "NULL", &cASN1Null, },
00458 { "OBJECT", &cASN1ObjectId, },
00459 { "OBJECT_DESCRIPTOR", NULL, },
00460 { "EXTERNAL", NULL, },
00461 { "REAL", NULL, },
00462 { "ENUMERATED", &cASN1Enumerated, },
00463 { "EMBEDDED_PDV", NULL, },
00464 { "UTF8STRING", &cASN1UTF8String, },
00465 { "RELATIVE_OID", NULL, },
00466 { "[UNIVERSAL 14]", NULL, },
00467 { "[UNIVERSAL 15]", NULL, },
00468 { "SEQUENCE", &cASN1Sequence, },
00469 { "SET", &cASN1Set, },
00470 { "NUMERICSTRING", &cASN1NumericString, },
00471 { "PRINTABLESTRING", &cASN1PrintableString, },
00472 { "T61STRING", &cASN1T61String, },
00473 { "VIDEOTEXSTRING", &cASN1VideotexString, },
00474 { "IA5STRING", &cASN1IA5String, },
00475 { "UTCTIME", &cASN1UTCTime, },
00476 { "GENERALIZEDTIME", &cASN1GeneralizedTime, },
00477 { "GRAPHICSTRING", &cASN1GraphicString, },
00478 { "ISO64STRING", &cASN1ISO64String, },
00479 { "GENERALSTRING", &cASN1GeneralString, },
00480 { "UNIVERSALSTRING", &cASN1UniversalString, },
00481 { "CHARACTER_STRING", NULL, },
00482 { "BMPSTRING", &cASN1BMPString, },
00483 };
00484
00485 int ossl_asn1_info_size = (sizeof(ossl_asn1_info)/sizeof(ossl_asn1_info[0]));
00486
00487 static int ossl_asn1_default_tag(VALUE obj);
00488
00489 ASN1_TYPE*
00490 ossl_asn1_get_asn1type(VALUE obj)
00491 {
00492 ASN1_TYPE *ret;
00493 VALUE value, rflag;
00494 void *ptr;
00495 void (*free_func)();
00496 long tag, flag;
00497
00498 tag = ossl_asn1_default_tag(obj);
00499 value = ossl_asn1_get_value(obj);
00500 switch(tag){
00501 case V_ASN1_BOOLEAN:
00502 ptr = (void*)(VALUE)obj_to_asn1bool(value);
00503 free_func = NULL;
00504 break;
00505 case V_ASN1_INTEGER:
00506 case V_ASN1_ENUMERATED:
00507 ptr = obj_to_asn1int(value);
00508 free_func = ASN1_INTEGER_free;
00509 break;
00510 case V_ASN1_BIT_STRING:
00511 rflag = rb_attr_get(obj, rb_intern("@unused_bits"));
00512 flag = NIL_P(rflag) ? -1 : NUM2INT(rflag);
00513 ptr = obj_to_asn1bstr(value, flag);
00514 free_func = ASN1_BIT_STRING_free;
00515 break;
00516 case V_ASN1_NULL:
00517 ptr = obj_to_asn1null(value);
00518 free_func = ASN1_NULL_free;
00519 break;
00520 case V_ASN1_OCTET_STRING:
00521 case V_ASN1_UTF8STRING:
00522 case V_ASN1_NUMERICSTRING:
00523 case V_ASN1_PRINTABLESTRING:
00524 case V_ASN1_T61STRING:
00525 case V_ASN1_VIDEOTEXSTRING:
00526 case V_ASN1_IA5STRING:
00527 case V_ASN1_GRAPHICSTRING:
00528 case V_ASN1_ISO64STRING:
00529 case V_ASN1_GENERALSTRING:
00530 case V_ASN1_UNIVERSALSTRING:
00531 case V_ASN1_BMPSTRING:
00532 ptr = obj_to_asn1str(value);
00533 free_func = ASN1_STRING_free;
00534 break;
00535 case V_ASN1_OBJECT:
00536 ptr = obj_to_asn1obj(value);
00537 free_func = ASN1_OBJECT_free;
00538 break;
00539 case V_ASN1_UTCTIME:
00540 ptr = obj_to_asn1utime(value);
00541 free_func = ASN1_TIME_free;
00542 break;
00543 case V_ASN1_GENERALIZEDTIME:
00544 ptr = obj_to_asn1gtime(value);
00545 free_func = ASN1_TIME_free;
00546 break;
00547 case V_ASN1_SET:
00548 case V_ASN1_SEQUENCE:
00549 ptr = obj_to_asn1derstr(obj);
00550 free_func = ASN1_STRING_free;
00551 break;
00552 default:
00553 ossl_raise(eASN1Error, "unsupported ASN.1 type");
00554 }
00555 if(!(ret = OPENSSL_malloc(sizeof(ASN1_TYPE)))){
00556 if(free_func) free_func(ptr);
00557 ossl_raise(eASN1Error, "ASN1_TYPE alloc failure");
00558 }
00559 memset(ret, 0, sizeof(ASN1_TYPE));
00560 ASN1_TYPE_set(ret, tag, ptr);
00561
00562 return ret;
00563 }
00564
00565 static int
00566 ossl_asn1_default_tag(VALUE obj)
00567 {
00568 int i;
00569
00570 for(i = 0; i < ossl_asn1_info_size; i++){
00571 if(ossl_asn1_info[i].klass &&
00572 rb_obj_is_kind_of(obj, *ossl_asn1_info[i].klass)){
00573 return i;
00574 }
00575 }
00576 ossl_raise(eASN1Error, "universal tag for %s not found",
00577 rb_class2name(CLASS_OF(obj)));
00578
00579 return -1;
00580 }
00581
00582 static int
00583 ossl_asn1_tag(VALUE obj)
00584 {
00585 VALUE tag;
00586
00587 tag = ossl_asn1_get_tag(obj);
00588 if(NIL_P(tag))
00589 ossl_raise(eASN1Error, "tag number not specified");
00590
00591 return NUM2INT(tag);
00592 }
00593
00594 static int
00595 ossl_asn1_is_explicit(VALUE obj)
00596 {
00597 VALUE s;
00598 int ret = -1;
00599
00600 s = ossl_asn1_get_tagging(obj);
00601 if(NIL_P(s)) return 0;
00602 else if(SYMBOL_P(s)){
00603 if (SYM2ID(s) == sIMPLICIT)
00604 ret = 0;
00605 else if (SYM2ID(s) == sEXPLICIT)
00606 ret = 1;
00607 }
00608 if(ret < 0){
00609 ossl_raise(eASN1Error, "invalid tag default");
00610 }
00611
00612 return ret;
00613 }
00614
00615 static int
00616 ossl_asn1_tag_class(VALUE obj)
00617 {
00618 VALUE s;
00619 int ret = -1;
00620
00621 s = ossl_asn1_get_tag_class(obj);
00622 if(NIL_P(s)) ret = V_ASN1_UNIVERSAL;
00623 else if(SYMBOL_P(s)){
00624 if (SYM2ID(s) == sUNIVERSAL)
00625 ret = V_ASN1_UNIVERSAL;
00626 else if (SYM2ID(s) == sAPPLICATION)
00627 ret = V_ASN1_APPLICATION;
00628 else if (SYM2ID(s) == sCONTEXT_SPECIFIC)
00629 ret = V_ASN1_CONTEXT_SPECIFIC;
00630 else if (SYM2ID(s) == sPRIVATE)
00631 ret = V_ASN1_PRIVATE;
00632 }
00633 if(ret < 0){
00634 ossl_raise(eASN1Error, "invalid tag class");
00635 }
00636
00637 return ret;
00638 }
00639
00640 static VALUE
00641 ossl_asn1_class2sym(int tc)
00642 {
00643 if((tc & V_ASN1_PRIVATE) == V_ASN1_PRIVATE)
00644 return ID2SYM(sPRIVATE);
00645 else if((tc & V_ASN1_CONTEXT_SPECIFIC) == V_ASN1_CONTEXT_SPECIFIC)
00646 return ID2SYM(sCONTEXT_SPECIFIC);
00647 else if((tc & V_ASN1_APPLICATION) == V_ASN1_APPLICATION)
00648 return ID2SYM(sAPPLICATION);
00649 else
00650 return ID2SYM(sUNIVERSAL);
00651 }
00652
00653 static VALUE
00654 ossl_asn1data_initialize(VALUE self, VALUE value, VALUE tag, VALUE tag_class)
00655 {
00656 if(!SYMBOL_P(tag_class))
00657 ossl_raise(eASN1Error, "invalid tag class");
00658 if((SYM2ID(tag_class) == sUNIVERSAL) && NUM2INT(tag) > 31)
00659 ossl_raise(eASN1Error, "tag number for Universal too large");
00660 ossl_asn1_set_tag(self, tag);
00661 ossl_asn1_set_value(self, value);
00662 ossl_asn1_set_tag_class(self, tag_class);
00663
00664 return self;
00665 }
00666
00667 static VALUE
00668 join_der_i(VALUE i, VALUE str)
00669 {
00670 i = ossl_to_der_if_possible(i);
00671 StringValue(i);
00672 rb_str_append(str, i);
00673 return Qnil;
00674 }
00675
00676 static VALUE
00677 join_der(VALUE enumerable)
00678 {
00679 VALUE str = rb_str_new(0, 0);
00680 rb_block_call(enumerable, rb_intern("each"), 0, 0, join_der_i, str);
00681 return str;
00682 }
00683
00684 static VALUE
00685 ossl_asn1data_to_der(VALUE self)
00686 {
00687 VALUE value, der;
00688 int tag, tag_class, is_cons = 0;
00689 long length;
00690 unsigned char *p;
00691
00692 value = ossl_asn1_get_value(self);
00693 if(rb_obj_is_kind_of(value, rb_cArray)){
00694 is_cons = 1;
00695 value = join_der(value);
00696 }
00697 StringValue(value);
00698
00699 tag = ossl_asn1_tag(self);
00700 tag_class = ossl_asn1_tag_class(self);
00701 if((length = ASN1_object_size(1, RSTRING_LEN(value), tag)) <= 0)
00702 ossl_raise(eASN1Error, NULL);
00703 der = rb_str_new(0, length);
00704 p = (unsigned char *)RSTRING_PTR(der);
00705 ASN1_put_object(&p, is_cons, RSTRING_LEN(value), tag, tag_class);
00706 memcpy(p, RSTRING_PTR(value), RSTRING_LEN(value));
00707 p += RSTRING_LEN(value);
00708 ossl_str_adjust(der, p);
00709
00710 return der;
00711 }
00712
00713 static VALUE
00714 ossl_asn1_decode0(unsigned char **pp, long length, long *offset, long depth,
00715 int once, int yield)
00716 {
00717 unsigned char *start, *p;
00718 const unsigned char *p0;
00719 long len, off = *offset;
00720 int hlen, tag, tc, j;
00721 VALUE ary, asn1data, value, tag_class;
00722
00723 ary = rb_ary_new();
00724 p = *pp;
00725 while(length > 0){
00726 start = p;
00727 p0 = p;
00728 j = ASN1_get_object(&p0, &len, &tag, &tc, length);
00729 p = (unsigned char *)p0;
00730 if(j & 0x80) ossl_raise(eASN1Error, NULL);
00731 hlen = p - start;
00732 if(yield){
00733 VALUE arg = rb_ary_new();
00734 rb_ary_push(arg, LONG2NUM(depth));
00735 rb_ary_push(arg, LONG2NUM(off));
00736 rb_ary_push(arg, LONG2NUM(hlen));
00737 rb_ary_push(arg, LONG2NUM(len));
00738 rb_ary_push(arg, (j & V_ASN1_CONSTRUCTED) ? Qtrue : Qfalse);
00739 rb_ary_push(arg, ossl_asn1_class2sym(tc));
00740 rb_ary_push(arg, INT2NUM(tag));
00741 rb_yield(arg);
00742 }
00743 length -= hlen;
00744 off += hlen;
00745 if(len > length) ossl_raise(eASN1Error, "value is too short");
00746 if((tc & V_ASN1_PRIVATE) == V_ASN1_PRIVATE)
00747 tag_class = sPRIVATE;
00748 else if((tc & V_ASN1_CONTEXT_SPECIFIC) == V_ASN1_CONTEXT_SPECIFIC)
00749 tag_class = sCONTEXT_SPECIFIC;
00750 else if((tc & V_ASN1_APPLICATION) == V_ASN1_APPLICATION)
00751 tag_class = sAPPLICATION;
00752 else
00753 tag_class = sUNIVERSAL;
00754 if(j & V_ASN1_CONSTRUCTED){
00755
00756 if((j == 0x21) && (len == 0)){
00757 long lastoff = off;
00758 value = ossl_asn1_decode0(&p, length, &off, depth+1, 0, yield);
00759 len = off - lastoff;
00760 }
00761 else value = ossl_asn1_decode0(&p, len, &off, depth+1, 0, yield);
00762 }
00763 else{
00764 value = rb_str_new((const char *)p, len);
00765 p += len;
00766 off += len;
00767 }
00768 if(tag_class == sUNIVERSAL &&
00769 tag < ossl_asn1_info_size && ossl_asn1_info[tag].klass){
00770 VALUE klass = *ossl_asn1_info[tag].klass;
00771 long flag = 0;
00772 if(!rb_obj_is_kind_of(value, rb_cArray)){
00773 switch(tag){
00774 case V_ASN1_BOOLEAN:
00775 value = decode_bool(start, hlen+len);
00776 break;
00777 case V_ASN1_INTEGER:
00778 value = decode_int(start, hlen+len);
00779 break;
00780 case V_ASN1_BIT_STRING:
00781 value = decode_bstr(start, hlen+len, &flag);
00782 break;
00783 case V_ASN1_NULL:
00784 value = decode_null(start, hlen+len);
00785 break;
00786 case V_ASN1_ENUMERATED:
00787 value = decode_enum(start, hlen+len);
00788 break;
00789 case V_ASN1_OBJECT:
00790 value = decode_obj(start, hlen+len);
00791 break;
00792 case V_ASN1_UTCTIME:
00793 case V_ASN1_GENERALIZEDTIME:
00794 value = decode_time(start, hlen+len);
00795 break;
00796 default:
00797
00798 break;
00799 }
00800 }
00801 asn1data = rb_funcall(klass, rb_intern("new"), 1, value);
00802 if(tag == V_ASN1_BIT_STRING){
00803 rb_iv_set(asn1data, "@unused_bits", LONG2NUM(flag));
00804 }
00805 }
00806 else{
00807 asn1data = rb_funcall(cASN1Data, rb_intern("new"), 3,
00808 value, INT2NUM(tag), ID2SYM(tag_class));
00809 }
00810 rb_ary_push(ary, asn1data);
00811 length -= len;
00812 if(once) break;
00813 }
00814 *pp = p;
00815 *offset = off;
00816
00817 return ary;
00818 }
00819
00820 static VALUE
00821 ossl_asn1_traverse(VALUE self, VALUE obj)
00822 {
00823 unsigned char *p;
00824 long offset = 0;
00825 volatile VALUE tmp;
00826
00827 obj = ossl_to_der_if_possible(obj);
00828 tmp = rb_str_new4(StringValue(obj));
00829 p = (unsigned char *)RSTRING_PTR(tmp);
00830 ossl_asn1_decode0(&p, RSTRING_LEN(tmp), &offset, 0, 0, 1);
00831
00832 return Qnil;
00833 }
00834
00835 static VALUE
00836 ossl_asn1_decode(VALUE self, VALUE obj)
00837 {
00838 VALUE ret, ary;
00839 unsigned char *p;
00840 long offset = 0;
00841 volatile VALUE tmp;
00842
00843 obj = ossl_to_der_if_possible(obj);
00844 tmp = rb_str_new4(StringValue(obj));
00845 p = (unsigned char *)RSTRING_PTR(tmp);
00846 ary = ossl_asn1_decode0(&p, RSTRING_LEN(tmp), &offset, 0, 1, 0);
00847 ret = rb_ary_entry(ary, 0);
00848
00849 return ret;
00850 }
00851
00852 static VALUE
00853 ossl_asn1_decode_all(VALUE self, VALUE obj)
00854 {
00855 VALUE ret;
00856 unsigned char *p;
00857 long offset = 0;
00858 volatile VALUE tmp;
00859
00860 obj = ossl_to_der_if_possible(obj);
00861 tmp = rb_str_new4(StringValue(obj));
00862 p = (unsigned char *)RSTRING_PTR(tmp);
00863 ret = ossl_asn1_decode0(&p, RSTRING_LEN(tmp), &offset, 0, 0, 0);
00864
00865 return ret;
00866 }
00867
00868 static VALUE
00869 ossl_asn1_initialize(int argc, VALUE *argv, VALUE self)
00870 {
00871 VALUE value, tag, tagging, tag_class;
00872
00873 rb_scan_args(argc, argv, "13", &value, &tag, &tagging, &tag_class);
00874 if(argc > 1){
00875 if(NIL_P(tag))
00876 ossl_raise(eASN1Error, "must specify tag number");
00877 if(NIL_P(tagging))
00878 tagging = ID2SYM(sEXPLICIT);
00879 if(!SYMBOL_P(tagging))
00880 ossl_raise(eASN1Error, "invalid tag default");
00881 if(NIL_P(tag_class))
00882 tag_class = ID2SYM(sCONTEXT_SPECIFIC);
00883 if(!SYMBOL_P(tag_class))
00884 ossl_raise(eASN1Error, "invalid tag class");
00885 if(SYM2ID(tagging) == sIMPLICIT && NUM2INT(tag) > 31)
00886 ossl_raise(eASN1Error, "tag number for Universal too large");
00887 }
00888 else{
00889 tag = INT2NUM(ossl_asn1_default_tag(self));
00890 tagging = Qnil;
00891 tag_class = ID2SYM(sUNIVERSAL);
00892 }
00893 ossl_asn1_set_tag(self, tag);
00894 ossl_asn1_set_value(self, value);
00895 ossl_asn1_set_tagging(self, tagging);
00896 ossl_asn1_set_tag_class(self, tag_class);
00897
00898 return self;
00899 }
00900
00901 static int
00902 ossl_i2d_ASN1_TYPE(ASN1_TYPE *a, unsigned char **pp)
00903 {
00904 #if OPENSSL_VERSION_NUMBER < 0x00907000L
00905 if(!a) return 0;
00906 if(a->type == V_ASN1_BOOLEAN)
00907 return i2d_ASN1_BOOLEAN(a->value.boolean, pp);
00908 #endif
00909 return i2d_ASN1_TYPE(a, pp);
00910 }
00911
00912 static void
00913 ossl_ASN1_TYPE_free(ASN1_TYPE *a)
00914 {
00915 #if OPENSSL_VERSION_NUMBER < 0x00907000L
00916 if(!a) return;
00917 if(a->type == V_ASN1_BOOLEAN){
00918 OPENSSL_free(a);
00919 return;
00920 }
00921 #endif
00922 ASN1_TYPE_free(a);
00923 }
00924
00925 static VALUE
00926 ossl_asn1prim_to_der(VALUE self)
00927 {
00928 ASN1_TYPE *asn1;
00929 int tn, tc, explicit;
00930 long len, reallen;
00931 unsigned char *buf, *p;
00932 VALUE str;
00933
00934 tn = NUM2INT(ossl_asn1_get_tag(self));
00935 tc = ossl_asn1_tag_class(self);
00936 explicit = ossl_asn1_is_explicit(self);
00937 asn1 = ossl_asn1_get_asn1type(self);
00938
00939 len = ASN1_object_size(1, ossl_i2d_ASN1_TYPE(asn1, NULL), tn);
00940 if(!(buf = OPENSSL_malloc(len))){
00941 ossl_ASN1_TYPE_free(asn1);
00942 ossl_raise(eASN1Error, "cannot alloc buffer");
00943 }
00944 p = buf;
00945 if (tc == V_ASN1_UNIVERSAL) {
00946 ossl_i2d_ASN1_TYPE(asn1, &p);
00947 } else if (explicit) {
00948 ASN1_put_object(&p, 1, ossl_i2d_ASN1_TYPE(asn1, NULL), tn, tc);
00949 ossl_i2d_ASN1_TYPE(asn1, &p);
00950 } else {
00951 ossl_i2d_ASN1_TYPE(asn1, &p);
00952 *buf = tc | tn | (*buf & V_ASN1_CONSTRUCTED);
00953 }
00954 ossl_ASN1_TYPE_free(asn1);
00955 reallen = p - buf;
00956 assert(reallen <= len);
00957 str = ossl_buf2str((char *)buf, reallen);
00958
00959 return str;
00960 }
00961
00962 static VALUE
00963 ossl_asn1cons_to_der(VALUE self)
00964 {
00965 int tag, tn, tc, explicit;
00966 long seq_len, length;
00967 unsigned char *p;
00968 VALUE value, str;
00969
00970 tag = ossl_asn1_default_tag(self);
00971 tn = NUM2INT(ossl_asn1_get_tag(self));
00972 tc = ossl_asn1_tag_class(self);
00973 explicit = ossl_asn1_is_explicit(self);
00974 value = join_der(ossl_asn1_get_value(self));
00975
00976 seq_len = ASN1_object_size(1, RSTRING_LEN(value), tag);
00977 length = ASN1_object_size(1, seq_len, tn);
00978 str = rb_str_new(0, length);
00979 p = (unsigned char *)RSTRING_PTR(str);
00980 if(tc == V_ASN1_UNIVERSAL)
00981 ASN1_put_object(&p, 1, RSTRING_LEN(value), tn, tc);
00982 else{
00983 if(explicit){
00984 ASN1_put_object(&p, 1, seq_len, tn, tc);
00985 ASN1_put_object(&p, 1, RSTRING_LEN(value), tag, V_ASN1_UNIVERSAL);
00986 }
00987 else ASN1_put_object(&p, 1, RSTRING_LEN(value), tn, tc);
00988 }
00989 memcpy(p, RSTRING_PTR(value), RSTRING_LEN(value));
00990 p += RSTRING_LEN(value);
00991 ossl_str_adjust(str, p);
00992
00993 return str;
00994 }
00995
00996 static VALUE
00997 ossl_asn1cons_each(VALUE self)
00998 {
00999 rb_ary_each(ossl_asn1_get_value(self));
01000 return self;
01001 }
01002
01003 static VALUE
01004 ossl_asn1obj_s_register(VALUE self, VALUE oid, VALUE sn, VALUE ln)
01005 {
01006 StringValue(oid);
01007 StringValue(sn);
01008 StringValue(ln);
01009
01010 if(!OBJ_create(RSTRING_PTR(oid), RSTRING_PTR(sn), RSTRING_PTR(ln)))
01011 ossl_raise(eASN1Error, NULL);
01012
01013 return Qtrue;
01014 }
01015
01016 static VALUE
01017 ossl_asn1obj_get_sn(VALUE self)
01018 {
01019 VALUE val, ret = Qnil;
01020 int nid;
01021
01022 val = ossl_asn1_get_value(self);
01023 if ((nid = OBJ_txt2nid(StringValuePtr(val))) != NID_undef)
01024 ret = rb_str_new2(OBJ_nid2sn(nid));
01025
01026 return ret;
01027 }
01028
01029 static VALUE
01030 ossl_asn1obj_get_ln(VALUE self)
01031 {
01032 VALUE val, ret = Qnil;
01033 int nid;
01034
01035 val = ossl_asn1_get_value(self);
01036 if ((nid = OBJ_txt2nid(StringValuePtr(val))) != NID_undef)
01037 ret = rb_str_new2(OBJ_nid2ln(nid));
01038
01039 return ret;
01040 }
01041
01042 static VALUE
01043 ossl_asn1obj_get_oid(VALUE self)
01044 {
01045 VALUE val;
01046 ASN1_OBJECT *a1obj;
01047 char buf[128];
01048
01049 val = ossl_asn1_get_value(self);
01050 a1obj = obj_to_asn1obj(val);
01051 OBJ_obj2txt(buf, sizeof(buf), a1obj, 1);
01052 ASN1_OBJECT_free(a1obj);
01053
01054 return rb_str_new2(buf);
01055 }
01056
01057 #define OSSL_ASN1_IMPL_FACTORY_METHOD(klass) \
01058 static VALUE ossl_asn1_##klass(int argc, VALUE *argv, VALUE self)\
01059 { return rb_funcall3(cASN1##klass, rb_intern("new"), argc, argv); }
01060
01061 OSSL_ASN1_IMPL_FACTORY_METHOD(Boolean)
01062 OSSL_ASN1_IMPL_FACTORY_METHOD(Integer)
01063 OSSL_ASN1_IMPL_FACTORY_METHOD(Enumerated)
01064 OSSL_ASN1_IMPL_FACTORY_METHOD(BitString)
01065 OSSL_ASN1_IMPL_FACTORY_METHOD(OctetString)
01066 OSSL_ASN1_IMPL_FACTORY_METHOD(UTF8String)
01067 OSSL_ASN1_IMPL_FACTORY_METHOD(NumericString)
01068 OSSL_ASN1_IMPL_FACTORY_METHOD(PrintableString)
01069 OSSL_ASN1_IMPL_FACTORY_METHOD(T61String)
01070 OSSL_ASN1_IMPL_FACTORY_METHOD(VideotexString)
01071 OSSL_ASN1_IMPL_FACTORY_METHOD(IA5String)
01072 OSSL_ASN1_IMPL_FACTORY_METHOD(GraphicString)
01073 OSSL_ASN1_IMPL_FACTORY_METHOD(ISO64String)
01074 OSSL_ASN1_IMPL_FACTORY_METHOD(GeneralString)
01075 OSSL_ASN1_IMPL_FACTORY_METHOD(UniversalString)
01076 OSSL_ASN1_IMPL_FACTORY_METHOD(BMPString)
01077 OSSL_ASN1_IMPL_FACTORY_METHOD(Null)
01078 OSSL_ASN1_IMPL_FACTORY_METHOD(ObjectId)
01079 OSSL_ASN1_IMPL_FACTORY_METHOD(UTCTime)
01080 OSSL_ASN1_IMPL_FACTORY_METHOD(GeneralizedTime)
01081 OSSL_ASN1_IMPL_FACTORY_METHOD(Sequence)
01082 OSSL_ASN1_IMPL_FACTORY_METHOD(Set)
01083
01084 void
01085 Init_ossl_asn1()
01086 {
01087 VALUE ary;
01088 int i;
01089
01090 #if 0
01091 mOSSL = rb_define_module("OpenSSL");
01092 #endif
01093
01094 sUNIVERSAL = rb_intern("UNIVERSAL");
01095 sCONTEXT_SPECIFIC = rb_intern("CONTEXT_SPECIFIC");
01096 sAPPLICATION = rb_intern("APPLICATION");
01097 sPRIVATE = rb_intern("PRIVATE");
01098 sEXPLICIT = rb_intern("EXPLICIT");
01099 sIMPLICIT = rb_intern("IMPLICIT");
01100
01101 mASN1 = rb_define_module_under(mOSSL, "ASN1");
01102 eASN1Error = rb_define_class_under(mASN1, "ASN1Error", eOSSLError);
01103 rb_define_module_function(mASN1, "traverse", ossl_asn1_traverse, 1);
01104 rb_define_module_function(mASN1, "decode", ossl_asn1_decode, 1);
01105 rb_define_module_function(mASN1, "decode_all", ossl_asn1_decode_all, 1);
01106 ary = rb_ary_new();
01107 rb_define_const(mASN1, "UNIVERSAL_TAG_NAME", ary);
01108 for(i = 0; i < ossl_asn1_info_size; i++){
01109 if(ossl_asn1_info[i].name[0] == '[') continue;
01110 rb_define_const(mASN1, ossl_asn1_info[i].name, INT2NUM(i));
01111 rb_ary_store(ary, i, rb_str_new2(ossl_asn1_info[i].name));
01112 }
01113
01114 cASN1Data = rb_define_class_under(mASN1, "ASN1Data", rb_cObject);
01115 rb_attr(cASN1Data, rb_intern("value"), 1, 1, 0);
01116 rb_attr(cASN1Data, rb_intern("tag"), 1, 1, 0);
01117 rb_attr(cASN1Data, rb_intern("tag_class"), 1, 1, 0);
01118 rb_define_method(cASN1Data, "initialize", ossl_asn1data_initialize, 3);
01119 rb_define_method(cASN1Data, "to_der", ossl_asn1data_to_der, 0);
01120
01121 cASN1Primitive = rb_define_class_under(mASN1, "Primitive", cASN1Data);
01122 rb_attr(cASN1Primitive, rb_intern("tagging"), 1, 1, Qtrue);
01123 rb_define_method(cASN1Primitive, "initialize", ossl_asn1_initialize, -1);
01124 rb_define_method(cASN1Primitive, "to_der", ossl_asn1prim_to_der, 0);
01125
01126 cASN1Constructive = rb_define_class_under(mASN1,"Constructive", cASN1Data);
01127 rb_include_module(cASN1Constructive, rb_mEnumerable);
01128 rb_attr(cASN1Constructive, rb_intern("tagging"), 1, 1, Qtrue);
01129 rb_define_method(cASN1Constructive, "initialize", ossl_asn1_initialize, -1);
01130 rb_define_method(cASN1Constructive, "to_der", ossl_asn1cons_to_der, 0);
01131 rb_define_method(cASN1Constructive, "each", ossl_asn1cons_each, 0);
01132
01133 #define OSSL_ASN1_DEFINE_CLASS(name, super) \
01134 do{\
01135 cASN1##name = rb_define_class_under(mASN1, #name, cASN1##super);\
01136 rb_define_module_function(mASN1, #name, ossl_asn1_##name, -1);\
01137 }while(0)
01138
01139 OSSL_ASN1_DEFINE_CLASS(Boolean, Primitive);
01140 OSSL_ASN1_DEFINE_CLASS(Integer, Primitive);
01141 OSSL_ASN1_DEFINE_CLASS(Enumerated, Primitive);
01142 OSSL_ASN1_DEFINE_CLASS(BitString, Primitive);
01143 OSSL_ASN1_DEFINE_CLASS(OctetString, Primitive);
01144 OSSL_ASN1_DEFINE_CLASS(UTF8String, Primitive);
01145 OSSL_ASN1_DEFINE_CLASS(NumericString, Primitive);
01146 OSSL_ASN1_DEFINE_CLASS(PrintableString, Primitive);
01147 OSSL_ASN1_DEFINE_CLASS(T61String, Primitive);
01148 OSSL_ASN1_DEFINE_CLASS(VideotexString, Primitive);
01149 OSSL_ASN1_DEFINE_CLASS(IA5String, Primitive);
01150 OSSL_ASN1_DEFINE_CLASS(GraphicString, Primitive);
01151 OSSL_ASN1_DEFINE_CLASS(ISO64String, Primitive);
01152 OSSL_ASN1_DEFINE_CLASS(GeneralString, Primitive);
01153 OSSL_ASN1_DEFINE_CLASS(UniversalString, Primitive);
01154 OSSL_ASN1_DEFINE_CLASS(BMPString, Primitive);
01155 OSSL_ASN1_DEFINE_CLASS(Null, Primitive);
01156 OSSL_ASN1_DEFINE_CLASS(ObjectId, Primitive);
01157 OSSL_ASN1_DEFINE_CLASS(UTCTime, Primitive);
01158 OSSL_ASN1_DEFINE_CLASS(GeneralizedTime, Primitive);
01159
01160 OSSL_ASN1_DEFINE_CLASS(Sequence, Constructive);
01161 OSSL_ASN1_DEFINE_CLASS(Set, Constructive);
01162
01163 rb_define_singleton_method(cASN1ObjectId, "register", ossl_asn1obj_s_register, 3);
01164 rb_define_method(cASN1ObjectId, "sn", ossl_asn1obj_get_sn, 0);
01165 rb_define_method(cASN1ObjectId, "ln", ossl_asn1obj_get_ln, 0);
01166 rb_define_method(cASN1ObjectId, "oid", ossl_asn1obj_get_oid, 0);
01167 rb_define_alias(cASN1ObjectId, "short_name", "sn");
01168 rb_define_alias(cASN1ObjectId, "long_name", "ln");
01169 rb_attr(cASN1BitString, rb_intern("unused_bits"), 1, 1, 0);
01170 }
01171