Skip to content

Commit d834e86

Browse files
authored
Merge pull request #161 from rhenium/ky/x509-implement-eq
x509*: implement ==
2 parents 897ee5e + 5c4af48 commit d834e86

File tree

8 files changed

+177
-0
lines changed

8 files changed

+177
-0
lines changed

ext/openssl/ossl_x509cert.c

Lines changed: 21 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -683,6 +683,26 @@ ossl_x509_inspect(VALUE self)
683683
ossl_x509_get_not_after(self));
684684
}
685685

686+
/*
687+
* call-seq:
688+
* cert1 == cert2 -> true | false
689+
*
690+
* Compares the two certificates. Note that this takes into account all fields,
691+
* not just the issuer name and the serial number.
692+
*/
693+
static VALUE
694+
ossl_x509_eq(VALUE self, VALUE other)
695+
{
696+
X509 *a, *b;
697+
698+
GetX509(self, a);
699+
if (!rb_obj_is_kind_of(other, cX509Cert))
700+
return Qfalse;
701+
GetX509(other, b);
702+
703+
return !X509_cmp(a, b) ? Qtrue : Qfalse;
704+
}
705+
686706
/*
687707
* INIT
688708
*/
@@ -821,4 +841,5 @@ Init_ossl_x509cert(void)
821841
rb_define_method(cX509Cert, "extensions=", ossl_x509_set_extensions, 1);
822842
rb_define_method(cX509Cert, "add_extension", ossl_x509_add_extension, 1);
823843
rb_define_method(cX509Cert, "inspect", ossl_x509_inspect, 0);
844+
rb_define_method(cX509Cert, "==", ossl_x509_eq, 1);
824845
}

ext/openssl/ossl_x509revoked.c

Lines changed: 21 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -249,6 +249,26 @@ ossl_x509revoked_add_extension(VALUE self, VALUE ext)
249249
return ext;
250250
}
251251

252+
static VALUE
253+
ossl_x509revoked_to_der(VALUE self)
254+
{
255+
X509_REVOKED *rev;
256+
VALUE str;
257+
int len;
258+
unsigned char *p;
259+
260+
GetX509Rev(self, rev);
261+
len = i2d_X509_REVOKED(rev, NULL);
262+
if (len <= 0)
263+
ossl_raise(eX509RevError, "i2d_X509_REVOKED");
264+
str = rb_str_new(NULL, len);
265+
p = (unsigned char *)RSTRING_PTR(str);
266+
if (i2d_X509_REVOKED(rev, &p) <= 0)
267+
ossl_raise(eX509RevError, "i2d_X509_REVOKED");
268+
ossl_str_adjust(str, p);
269+
return str;
270+
}
271+
252272
/*
253273
* INIT
254274
*/
@@ -276,4 +296,5 @@ Init_ossl_x509revoked(void)
276296
rb_define_method(cX509Rev, "extensions", ossl_x509revoked_get_extensions, 0);
277297
rb_define_method(cX509Rev, "extensions=", ossl_x509revoked_set_extensions, 1);
278298
rb_define_method(cX509Rev, "add_extension", ossl_x509revoked_add_extension, 1);
299+
rb_define_method(cX509Rev, "to_der", ossl_x509revoked_to_der, 0);
279300
}

lib/openssl/x509.rb

Lines changed: 33 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -41,6 +41,11 @@ def create_ext_from_hash(hash)
4141
end
4242

4343
class Extension
44+
def ==(other)
45+
return false unless Extension === other
46+
to_der == other.to_der
47+
end
48+
4449
def to_s # "oid = critical, value"
4550
str = self.oid
4651
str << " = "
@@ -160,6 +165,13 @@ def pretty_print(q)
160165
end
161166
end
162167

168+
class Attribute
169+
def ==(other)
170+
return false unless Attribute === other
171+
to_der == other.to_der
172+
end
173+
end
174+
163175
class StoreContext
164176
def cleanup
165177
warn "(#{caller.first}) OpenSSL::X509::StoreContext#cleanup is deprecated with no replacement" if $VERBOSE
@@ -178,5 +190,26 @@ def pretty_print(q)
178190
}
179191
end
180192
end
193+
194+
class CRL
195+
def ==(other)
196+
return false unless CRL === other
197+
to_der == other.to_der
198+
end
199+
end
200+
201+
class Revoked
202+
def ==(other)
203+
return false unless Revoked === other
204+
to_der == other.to_der
205+
end
206+
end
207+
208+
class Request
209+
def ==(other)
210+
return false unless Request === other
211+
to_der == other.to_der
212+
end
213+
end
181214
end
182215
end

test/test_x509attr.rb

Lines changed: 17 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -62,6 +62,23 @@ def test_dup
6262
attr = OpenSSL::X509::Attribute.new("challengePassword", val)
6363
assert_equal(attr.to_der, attr.dup.to_der)
6464
end
65+
66+
def test_eq
67+
val1 = OpenSSL::ASN1::Set([
68+
OpenSSL::ASN1::UTF8String("abc123")
69+
])
70+
attr1 = OpenSSL::X509::Attribute.new("challengePassword", val1)
71+
attr2 = OpenSSL::X509::Attribute.new("challengePassword", val1)
72+
ef = OpenSSL::X509::ExtensionFactory.new
73+
val2 = OpenSSL::ASN1::Set.new([OpenSSL::ASN1::Sequence.new([
74+
ef.create_extension("keyUsage", "keyCertSign", true)
75+
])])
76+
attr3 = OpenSSL::X509::Attribute.new("extReq", val2)
77+
78+
assert_equal false, attr1 == 12345
79+
assert_equal true, attr1 == attr2
80+
assert_equal false, attr1 == attr3
81+
end
6582
end
6683

6784
end

test/test_x509cert.rb

Lines changed: 14 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -169,6 +169,20 @@ def test_read_from_file
169169
}
170170
end
171171

172+
def test_eq
173+
cacert = issue_cert(@ca, @rsa1024, 1, [], nil, nil)
174+
cert1 = issue_cert(@ee1, @rsa2048, 2, [], cacert, @rsa1024)
175+
cert2 = issue_cert(@ee1, @rsa2048, 2, [], cacert, @rsa1024)
176+
cert3 = issue_cert(@ee1, @rsa2048, 3, [], cacert, @rsa1024)
177+
cert4 = issue_cert(@ee1, @rsa2048, 2, [], cacert, @rsa1024, digest: "sha512")
178+
179+
assert_equal false, cert1 == 12345
180+
assert_equal true, cert1 == cert2
181+
assert_equal false, cert1 == cert3
182+
assert_equal false, cert1 == cert4
183+
assert_equal false, cert3 == cert4
184+
end
185+
172186
private
173187

174188
def certificate_error_returns_false

test/test_x509crl.rb

Lines changed: 50 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -197,6 +197,56 @@ def test_sign_and_verify
197197
assert_equal(false, crl.verify(@dsa512))
198198
end
199199

200+
def test_revoked_to_der
201+
# revokedCertificates SEQUENCE OF SEQUENCE {
202+
# userCertificate CertificateSerialNumber,
203+
# revocationDate Time,
204+
# crlEntryExtensions Extensions OPTIONAL
205+
# -- if present, version MUST be v2
206+
# } OPTIONAL,
207+
208+
now = Time.utc(2000, 1, 1)
209+
rev1 = OpenSSL::X509::Revoked.new
210+
rev1.serial = 123
211+
rev1.time = now
212+
ext = OpenSSL::X509::Extension.new("CRLReason", OpenSSL::ASN1::Enumerated(1))
213+
rev1.extensions = [ext]
214+
asn1 = OpenSSL::ASN1::Sequence([
215+
OpenSSL::ASN1::Integer(123),
216+
OpenSSL::ASN1::UTCTime(now),
217+
OpenSSL::ASN1::Sequence([ext.to_der])
218+
])
219+
220+
assert_equal asn1.to_der, rev1.to_der
221+
end
222+
223+
def test_eq
224+
cacert = issue_cert(@ca, @rsa1024, 1, [], nil, nil)
225+
crl1 = issue_crl([], 1, Time.now, Time.now + 3600, [], cacert, @rsa1024, "sha256")
226+
rev1 = OpenSSL::X509::Revoked.new.tap { |rev|
227+
rev.serial = 1
228+
rev.time = Time.now
229+
}
230+
crl1.add_revoked(rev1)
231+
crl2 = OpenSSL::X509::CRL.new(crl1.to_der)
232+
233+
# CRL
234+
assert_equal false, crl1 == 12345
235+
assert_equal true, crl1 == crl2
236+
rev2 = OpenSSL::X509::Revoked.new.tap { |rev|
237+
rev.serial = 2
238+
rev.time = Time.now
239+
}
240+
crl2.add_revoked(rev2)
241+
assert_equal false, crl1 == crl2
242+
243+
# Revoked
244+
assert_equal false, rev1 == 12345
245+
assert_equal true, rev1 == crl2.revoked[0]
246+
assert_equal false, rev1 == crl2.revoked[1]
247+
assert_equal true, rev2 == crl2.revoked[1]
248+
end
249+
200250
private
201251

202252
def crl_error_returns_false

test/test_x509ext.rb

Lines changed: 11 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -75,6 +75,17 @@ def test_dup
7575
assert_equal(@basic_constraints.to_der, ext.to_der)
7676
assert_equal(ext.to_der, ext.dup.to_der)
7777
end
78+
79+
def test_eq
80+
ext1 = OpenSSL::X509::Extension.new(@basic_constraints.to_der)
81+
ef = OpenSSL::X509::ExtensionFactory.new
82+
ext2 = ef.create_extension("basicConstraints", "critical, CA:TRUE, pathlen:2")
83+
ext3 = ef.create_extension("basicConstraints", "critical, CA:TRUE")
84+
85+
assert_equal false, ext1 == 12345
86+
assert_equal true, ext1 == ext2
87+
assert_equal false, ext1 == ext3
88+
end
7889
end
7990

8091
end

test/test_x509req.rb

Lines changed: 10 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -141,6 +141,16 @@ def test_dup
141141
assert_equal(req.to_der, req.dup.to_der)
142142
end
143143

144+
def test_eq
145+
req1 = issue_csr(0, @dn, @rsa1024, "sha1")
146+
req2 = issue_csr(0, @dn, @rsa1024, "sha1")
147+
req3 = issue_csr(0, @dn, @rsa1024, "sha256")
148+
149+
assert_equal false, req1 == 12345
150+
assert_equal true, req1 == req2
151+
assert_equal false, req1 == req3
152+
end
153+
144154
private
145155

146156
def request_error_returns_false

0 commit comments

Comments
 (0)