Skip to content

Commit 2ea36c2

Browse files
committed
asn1: refactor converting ASN1_OBJECT to string
ruby/openssl exposes OIDs to Ruby as strings in many places, but the conversion logic has been duplicated and the behavior is inconsistent. There are mainly two patterns: - Returns the short name associated with the OID/NID, or the dotted decimal notation if it is unknown to OpenSSL. - Returns the long name, or the dotted decimal notation. These patterns are implemented using different OpenSSL APIs and that caused subtle differences. Add helper functions ossl_asn1obj_to_string() and ossl_asn1obj_to_string_long_name() to unify the logic. Also, document the current behaviors where it is not yet done. The inconsistency was likely unintentional, but since it dates back to the original implementations, standardizing it now would cause more issues than it resolves.
1 parent dcb05c4 commit 2ea36c2

File tree

15 files changed

+139
-160
lines changed

15 files changed

+139
-160
lines changed

ext/openssl/ossl_asn1.c

Lines changed: 56 additions & 35 deletions
Original file line numberDiff line numberDiff line change
@@ -147,6 +147,48 @@ asn1integer_to_num_i(VALUE arg)
147147
return asn1integer_to_num((ASN1_INTEGER *)arg);
148148
}
149149

150+
/*
151+
* ASN1_OBJECT conversions
152+
*/
153+
VALUE
154+
ossl_asn1obj_to_string_oid(const ASN1_OBJECT *a1obj)
155+
{
156+
VALUE str;
157+
int len;
158+
159+
str = rb_usascii_str_new(NULL, 127);
160+
len = OBJ_obj2txt(RSTRING_PTR(str), RSTRING_LENINT(str), a1obj, 1);
161+
if (len <= 0 || len == INT_MAX)
162+
ossl_raise(eOSSLError, "OBJ_obj2txt");
163+
if (len > RSTRING_LEN(str)) {
164+
/* +1 is for the \0 terminator added by OBJ_obj2txt() */
165+
rb_str_resize(str, len + 1);
166+
len = OBJ_obj2txt(RSTRING_PTR(str), len + 1, a1obj, 1);
167+
if (len <= 0)
168+
ossl_raise(eOSSLError, "OBJ_obj2txt");
169+
}
170+
rb_str_set_len(str, len);
171+
return str;
172+
}
173+
174+
VALUE
175+
ossl_asn1obj_to_string(const ASN1_OBJECT *obj)
176+
{
177+
int nid = OBJ_obj2nid(obj);
178+
if (nid != NID_undef)
179+
return rb_str_new_cstr(OBJ_nid2sn(nid));
180+
return ossl_asn1obj_to_string_oid(obj);
181+
}
182+
183+
VALUE
184+
ossl_asn1obj_to_string_long_name(const ASN1_OBJECT *obj)
185+
{
186+
int nid = OBJ_obj2nid(obj);
187+
if (nid != NID_undef)
188+
return rb_str_new_cstr(OBJ_nid2ln(nid));
189+
return ossl_asn1obj_to_string_oid(obj);
190+
}
191+
150192
/********/
151193
/*
152194
* ASN1 module
@@ -393,32 +435,27 @@ decode_null(unsigned char* der, long length)
393435
return Qnil;
394436
}
395437

438+
VALUE
439+
asn1obj_to_string_i(VALUE arg)
440+
{
441+
return ossl_asn1obj_to_string((const ASN1_OBJECT *)arg);
442+
}
443+
396444
static VALUE
397445
decode_obj(unsigned char* der, long length)
398446
{
399447
ASN1_OBJECT *obj;
400448
const unsigned char *p;
401449
VALUE ret;
402-
int nid;
403-
BIO *bio;
450+
int state;
404451

405452
p = der;
406-
if(!(obj = d2i_ASN1_OBJECT(NULL, &p, length)))
407-
ossl_raise(eASN1Error, NULL);
408-
if((nid = OBJ_obj2nid(obj)) != NID_undef){
409-
ASN1_OBJECT_free(obj);
410-
ret = rb_str_new2(OBJ_nid2sn(nid));
411-
}
412-
else{
413-
if(!(bio = BIO_new(BIO_s_mem()))){
414-
ASN1_OBJECT_free(obj);
415-
ossl_raise(eASN1Error, NULL);
416-
}
417-
i2a_ASN1_OBJECT(bio, obj);
418-
ASN1_OBJECT_free(obj);
419-
ret = ossl_membio2str(bio);
420-
}
421-
453+
if (!(obj = d2i_ASN1_OBJECT(NULL, &p, length)))
454+
ossl_raise(eASN1Error, "d2i_ASN1_OBJECT");
455+
ret = rb_protect(asn1obj_to_string_i, (VALUE)obj, &state);
456+
ASN1_OBJECT_free(obj);
457+
if (state)
458+
rb_jump_tag(state);
422459
return ret;
423460
}
424461

@@ -1172,23 +1209,7 @@ ossl_asn1obj_get_ln(VALUE self)
11721209
static VALUE
11731210
asn1obj_get_oid_i(VALUE vobj)
11741211
{
1175-
ASN1_OBJECT *a1obj = (void *)vobj;
1176-
VALUE str;
1177-
int len;
1178-
1179-
str = rb_usascii_str_new(NULL, 127);
1180-
len = OBJ_obj2txt(RSTRING_PTR(str), RSTRING_LENINT(str), a1obj, 1);
1181-
if (len <= 0 || len == INT_MAX)
1182-
ossl_raise(eASN1Error, "OBJ_obj2txt");
1183-
if (len > RSTRING_LEN(str)) {
1184-
/* +1 is for the \0 terminator added by OBJ_obj2txt() */
1185-
rb_str_resize(str, len + 1);
1186-
len = OBJ_obj2txt(RSTRING_PTR(str), len + 1, a1obj, 1);
1187-
if (len <= 0)
1188-
ossl_raise(eASN1Error, "OBJ_obj2txt");
1189-
}
1190-
rb_str_set_len(str, len);
1191-
return str;
1212+
return ossl_asn1obj_to_string_oid((const ASN1_OBJECT *)vobj);
11921213
}
11931214

11941215
/*

ext/openssl/ossl_asn1.h

Lines changed: 10 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -35,6 +35,16 @@ ASN1_INTEGER *num_to_asn1integer(VALUE, ASN1_INTEGER *);
3535
* ASN1_OBJECT conversions
3636
*/
3737
ASN1_OBJECT *ossl_to_asn1obj(VALUE obj);
38+
/*
39+
* Returns the short name if available, the dotted decimal notation otherwise.
40+
* This is the most common way to return ASN1_OBJECT to Ruby.
41+
*/
42+
VALUE ossl_asn1obj_to_string(const ASN1_OBJECT *a1obj);
43+
/*
44+
* However, some places use long names instead. This is likely unintentional,
45+
* but we keep the current behavior in existing methods.
46+
*/
47+
VALUE ossl_asn1obj_to_string_long_name(const ASN1_OBJECT *a1obj);
3848

3949
/*
4050
* ASN1 module

ext/openssl/ossl_ocsp.c

Lines changed: 1 addition & 10 deletions
Original file line numberDiff line numberDiff line change
@@ -1591,19 +1591,10 @@ ossl_ocspcid_get_hash_algorithm(VALUE self)
15911591
{
15921592
OCSP_CERTID *id;
15931593
ASN1_OBJECT *oid;
1594-
BIO *out;
15951594

15961595
GetOCSPCertId(self, id);
15971596
OCSP_id_get0_info(NULL, &oid, NULL, NULL, id);
1598-
1599-
if (!(out = BIO_new(BIO_s_mem())))
1600-
ossl_raise(eOCSPError, "BIO_new");
1601-
1602-
if (!i2a_ASN1_OBJECT(out, oid)) {
1603-
BIO_free(out);
1604-
ossl_raise(eOCSPError, "i2a_ASN1_OBJECT");
1605-
}
1606-
return ossl_membio2str(out);
1597+
return ossl_asn1obj_to_string_long_name(oid);
16071598
}
16081599

16091600
/*

ext/openssl/ossl_ts.c

Lines changed: 4 additions & 25 deletions
Original file line numberDiff line numberDiff line change
@@ -138,27 +138,6 @@ obj_to_asn1obj_i(VALUE obj)
138138
return (VALUE)ossl_to_asn1obj(obj);
139139
}
140140

141-
static VALUE
142-
get_asn1obj(const ASN1_OBJECT *obj)
143-
{
144-
BIO *out;
145-
VALUE ret;
146-
int nid;
147-
if ((nid = OBJ_obj2nid(obj)) != NID_undef)
148-
ret = rb_str_new2(OBJ_nid2sn(nid));
149-
else{
150-
if (!(out = BIO_new(BIO_s_mem())))
151-
ossl_raise(eTimestampError, "BIO_new(BIO_s_mem())");
152-
if (i2a_ASN1_OBJECT(out, obj) <= 0) {
153-
BIO_free(out);
154-
ossl_raise(eTimestampError, "i2a_ASN1_OBJECT");
155-
}
156-
ret = ossl_membio2str(out);
157-
}
158-
159-
return ret;
160-
}
161-
162141
static VALUE
163142
ossl_ts_req_alloc(VALUE klass)
164143
{
@@ -229,7 +208,7 @@ ossl_ts_req_get_algorithm(VALUE self)
229208
mi = TS_REQ_get_msg_imprint(req);
230209
algor = TS_MSG_IMPRINT_get_algo(mi);
231210
X509_ALGOR_get0(&obj, NULL, NULL, algor);
232-
return get_asn1obj(obj);
211+
return ossl_asn1obj_to_string(obj);
233212
}
234213

235214
/*
@@ -358,7 +337,7 @@ ossl_ts_req_get_policy_id(VALUE self)
358337
GetTSRequest(self, req);
359338
if (!TS_REQ_get_policy_id(req))
360339
return Qnil;
361-
return get_asn1obj(TS_REQ_get_policy_id(req));
340+
return ossl_asn1obj_to_string(TS_REQ_get_policy_id(req));
362341
}
363342

364343
/*
@@ -948,7 +927,7 @@ ossl_ts_token_info_get_policy_id(VALUE self)
948927
TS_TST_INFO *info;
949928

950929
GetTSTokenInfo(self, info);
951-
return get_asn1obj(TS_TST_INFO_get_policy_id(info));
930+
return ossl_asn1obj_to_string(TS_TST_INFO_get_policy_id(info));
952931
}
953932

954933
/*
@@ -976,7 +955,7 @@ ossl_ts_token_info_get_algorithm(VALUE self)
976955
mi = TS_TST_INFO_get_msg_imprint(info);
977956
algo = TS_MSG_IMPRINT_get_algo(mi);
978957
X509_ALGOR_get0(&obj, NULL, NULL, algo);
979-
return get_asn1obj(obj);
958+
return ossl_asn1obj_to_string(obj);
980959
}
981960

982961
/*

ext/openssl/ossl_x509attr.c

Lines changed: 5 additions & 16 deletions
Original file line numberDiff line numberDiff line change
@@ -164,29 +164,18 @@ ossl_x509attr_set_oid(VALUE self, VALUE oid)
164164

165165
/*
166166
* call-seq:
167-
* attr.oid => string
167+
* attr.oid -> string
168+
*
169+
* Returns the OID of the attribute. Returns the short name or the dotted
170+
* decimal notation.
168171
*/
169172
static VALUE
170173
ossl_x509attr_get_oid(VALUE self)
171174
{
172175
X509_ATTRIBUTE *attr;
173-
ASN1_OBJECT *oid;
174-
BIO *out;
175-
VALUE ret;
176-
int nid;
177176

178177
GetX509Attr(self, attr);
179-
oid = X509_ATTRIBUTE_get0_object(attr);
180-
if ((nid = OBJ_obj2nid(oid)) != NID_undef)
181-
ret = rb_str_new2(OBJ_nid2sn(nid));
182-
else{
183-
if (!(out = BIO_new(BIO_s_mem())))
184-
ossl_raise(eX509AttrError, NULL);
185-
i2a_ASN1_OBJECT(out, oid);
186-
ret = ossl_membio2str(out);
187-
}
188-
189-
return ret;
178+
return ossl_asn1obj_to_string(X509_ATTRIBUTE_get0_object(attr));
190179
}
191180

192181
/*

ext/openssl/ossl_x509cert.c

Lines changed: 8 additions & 12 deletions
Original file line numberDiff line numberDiff line change
@@ -318,27 +318,23 @@ ossl_x509_set_serial(VALUE self, VALUE num)
318318
/*
319319
* call-seq:
320320
* cert.signature_algorithm => string
321+
*
322+
* Returns the signature algorithm used to sign this certificate. This returns
323+
* the algorithm name found in the TBSCertificate structure, not the outer
324+
* \Certificate structure.
325+
*
326+
* Returns the long name of the signature algorithm, or the dotted decimal
327+
* notation if \OpenSSL does not define a long name for it.
321328
*/
322329
static VALUE
323330
ossl_x509_get_signature_algorithm(VALUE self)
324331
{
325332
X509 *x509;
326-
BIO *out;
327333
const ASN1_OBJECT *obj;
328-
VALUE str;
329334

330335
GetX509(self, x509);
331-
out = BIO_new(BIO_s_mem());
332-
if (!out) ossl_raise(eX509CertError, NULL);
333-
334336
X509_ALGOR_get0(&obj, NULL, NULL, X509_get0_tbs_sigalg(x509));
335-
if (!i2a_ASN1_OBJECT(out, obj)) {
336-
BIO_free(out);
337-
ossl_raise(eX509CertError, NULL);
338-
}
339-
str = ossl_membio2str(out);
340-
341-
return str;
337+
return ossl_asn1obj_to_string_long_name(obj);
342338
}
343339

344340
/*

ext/openssl/ossl_x509crl.c

Lines changed: 10 additions & 10 deletions
Original file line numberDiff line numberDiff line change
@@ -166,26 +166,26 @@ ossl_x509crl_set_version(VALUE self, VALUE version)
166166
return version;
167167
}
168168

169+
/*
170+
* call-seq:
171+
* crl.signature_algorithm -> string
172+
*
173+
* Returns the signature algorithm used to sign this CRL.
174+
*
175+
* Returns the long name of the signature algorithm, or the dotted decimal
176+
* notation if \OpenSSL does not define a long name for it.
177+
*/
169178
static VALUE
170179
ossl_x509crl_get_signature_algorithm(VALUE self)
171180
{
172181
X509_CRL *crl;
173182
const X509_ALGOR *alg;
174183
const ASN1_OBJECT *obj;
175-
BIO *out;
176184

177185
GetX509CRL(self, crl);
178-
if (!(out = BIO_new(BIO_s_mem()))) {
179-
ossl_raise(eX509CRLError, NULL);
180-
}
181186
X509_CRL_get0_signature(crl, NULL, &alg);
182187
X509_ALGOR_get0(&obj, NULL, NULL, alg);
183-
if (!i2a_ASN1_OBJECT(out, obj)) {
184-
BIO_free(out);
185-
ossl_raise(eX509CRLError, NULL);
186-
}
187-
188-
return ossl_membio2str(out);
188+
return ossl_asn1obj_to_string_long_name(obj);
189189
}
190190

191191
static VALUE

ext/openssl/ossl_x509ext.c

Lines changed: 8 additions & 15 deletions
Original file line numberDiff line numberDiff line change
@@ -359,27 +359,20 @@ ossl_x509ext_set_critical(VALUE self, VALUE flag)
359359
return flag;
360360
}
361361

362+
/*
363+
* call-seq:
364+
* ext.oid -> string
365+
*
366+
* Returns the OID of the extension. Returns the short name or the dotted
367+
* decimal notation.
368+
*/
362369
static VALUE
363370
ossl_x509ext_get_oid(VALUE obj)
364371
{
365372
X509_EXTENSION *ext;
366-
ASN1_OBJECT *extobj;
367-
BIO *out;
368-
VALUE ret;
369-
int nid;
370373

371374
GetX509Ext(obj, ext);
372-
extobj = X509_EXTENSION_get_object(ext);
373-
if ((nid = OBJ_obj2nid(extobj)) != NID_undef)
374-
ret = rb_str_new2(OBJ_nid2sn(nid));
375-
else{
376-
if (!(out = BIO_new(BIO_s_mem())))
377-
ossl_raise(eX509ExtError, NULL);
378-
i2a_ASN1_OBJECT(out, extobj);
379-
ret = ossl_membio2str(out);
380-
}
381-
382-
return ret;
375+
return ossl_asn1obj_to_string(X509_EXTENSION_get_object(ext));
383376
}
384377

385378
static VALUE

0 commit comments

Comments
 (0)