Skip to content

Commit cd0d8ce

Browse files
committed
[fix] handle uninitialized Digest/HMAC objects
1 parent a8da85f commit cd0d8ce

5 files changed

Lines changed: 82 additions & 12 deletions

File tree

‎src/main/java/org/jruby/ext/openssl/Digest.java‎

Lines changed: 18 additions & 11 deletions
Original file line numberDiff line numberDiff line change
@@ -158,12 +158,15 @@ String getRealName() {
158158
return osslToJava(name);
159159
}
160160

161-
MessageDigest getDigestImpl() {
161+
MessageDigest getDigest() {
162+
if (digest == null) {
163+
throw getRuntime().newRuntimeError("Digest CTX wasn't initialized!");
164+
}
162165
return digest;
163166
}
164167

165168
public String getName() {
166-
return name.toString();
169+
return name != null ? name.toString() : null;
167170
}
168171

169172
@JRubyMethod(required = 1, optional = 1, visibility = Visibility.PRIVATE)
@@ -186,9 +189,10 @@ public IRubyObject initialize_copy(final IRubyObject obj) {
186189
checkFrozen();
187190
if ( this == obj ) return this;
188191
final Digest that = ((Digest) obj);
192+
final MessageDigest thatDigest = that.getDigest();
189193
this.name = (RubyString) that.name.dup();
190194
try {
191-
this.digest = (MessageDigest) that.digest.clone();
195+
this.digest = (MessageDigest) thatDigest.clone();
192196
}
193197
catch (CloneNotSupportedException e) {
194198
final Ruby runtime = getRuntime();
@@ -201,36 +205,39 @@ public IRubyObject initialize_copy(final IRubyObject obj) {
201205
@JRubyMethod(name = "update", alias = "<<")
202206
public IRubyObject update(final IRubyObject obj) {
203207
final ByteList bytes = obj.asString().getByteList();
204-
digest.update(bytes.getUnsafeBytes(), bytes.getBegin(), bytes.getRealSize());
208+
getDigest().update(bytes.getUnsafeBytes(), bytes.getBegin(), bytes.getRealSize());
205209
return this;
206210
}
207211

208212
@JRubyMethod
209213
public IRubyObject reset() {
210-
digest.reset();
214+
getDigest().reset();
211215
return this;
212216
}
213217

214218
@JRubyMethod
215219
public RubyString finish() {
216-
final byte[] hash = digest.digest();
217-
digest.reset();
220+
final MessageDigest md = getDigest();
221+
final byte[] hash = md.digest();
222+
md.reset();
218223
return newString(getRuntime(), hash);
219224
}
220225

221226
@JRubyMethod
222-
public RubyString name() { return name; }
227+
public RubyString name() {
228+
return name;
229+
}
223230

224231
@JRubyMethod
225232
public IRubyObject digest_length() {
226-
return RubyFixnum.newFixnum(getRuntime(), digest.getDigestLength());
233+
return RubyFixnum.newFixnum(getRuntime(), getDigest().getDigestLength());
227234
}
228235

229236
@JRubyMethod
230237
public RubyInteger block_length(final ThreadContext context) {
231238
final Ruby runtime = context.runtime;
232239

233-
final int blockLength = getBlockLength( digest.getAlgorithm() );
240+
final int blockLength = getBlockLength( getDigest().getAlgorithm() );
234241

235242
if ( blockLength == -1 ) {
236243
throw runtime.newRuntimeError(getMetaClass() + " doesn't implement block_length()");
@@ -239,7 +246,7 @@ public RubyInteger block_length(final ThreadContext context) {
239246
}
240247

241248
String getAlgorithm() {
242-
return this.digest.getAlgorithm();
249+
return getDigest().getAlgorithm();
243250
}
244251

245252
String getShortAlgorithm() {

‎src/main/java/org/jruby/ext/openssl/HMAC.java‎

Lines changed: 20 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -164,6 +164,13 @@ public IRubyObject initialize_copy(final IRubyObject obj) {
164164
checkFrozen();
165165

166166
final HMAC that = ((HMAC) obj);
167+
if ( that.mac == null ) {
168+
this.mac = null;
169+
this.key = null;
170+
this.data = that.data != null ? new ByteList(that.data) : new ByteList(64);
171+
return this;
172+
}
173+
167174
final String algName = that.mac.getAlgorithm();
168175
try {
169176
this.mac = SecurityHelper.getMac(algName);
@@ -188,12 +195,18 @@ public IRubyObject initialize_copy(final IRubyObject obj) {
188195

189196
@JRubyMethod(name = { "update", "<<" })
190197
public IRubyObject update(final IRubyObject obj) {
198+
if ( mac == null ) {
199+
throw newHMACError(getRuntime(), "EVP_DigestSignUpdate");
200+
}
191201
data.append(obj.convertToString().getByteList());
192202
return this;
193203
}
194204

195205
@JRubyMethod
196206
public IRubyObject reset() {
207+
if ( mac == null ) {
208+
throw newHMACError(getRuntime(), "HMAC wasn't initialized");
209+
}
197210
data = new ByteList(64);
198211
return this;
199212
}
@@ -209,6 +222,9 @@ public IRubyObject hexdigest() {
209222
}
210223

211224
private byte[] getSignatureBytes() {
225+
if ( mac == null ) {
226+
throw newHMACError(getRuntime(), "EVP_DigestSignFinal: initialization error");
227+
}
212228
try {
213229
mac.reset();
214230
mac.update(data.getUnsafeBytes(), data.getBegin(), data.getRealSize());
@@ -249,6 +265,10 @@ public Object toJava(Class target) {
249265
return super.toJava(target);
250266
}
251267

268+
static RaiseException newHMACError(Ruby runtime, String message) {
269+
return newHMACError(runtime, message, null);
270+
}
271+
252272
private static RaiseException newHMACError(Ruby runtime, String message, Throwable cause) {
253273
return newError(runtime, runtime.getModule("OpenSSL").getClass("HMACError"), message, cause);
254274
}

‎src/main/java/org/jruby/ext/openssl/PKCS7.java‎

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -826,7 +826,7 @@ public IRubyObject initialize(final ThreadContext context,
826826
this.info = new SignerInfoWithPkey();
827827
final X509AuxCertificate cert = ((X509Cert) arg1).getAuxCert();
828828
final PrivateKey pkey = ((PKey) arg2).getPrivateKey();
829-
final java.security.MessageDigest digest = Digest.getDigest(context, arg3).getDigestImpl();
829+
final java.security.MessageDigest digest = Digest.getDigest(context, arg3).getDigest();
830830

831831
try {
832832
info.set(cert, pkey, digest);

‎test/test_digest.rb‎

Lines changed: 22 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -100,6 +100,28 @@ def test_dup
100100
assert_equal(@d1.digest, @d1.clone.digest, "clone .digest")
101101
end
102102

103+
def test_uninitialized_copy
104+
uninit = OpenSSL::Digest.allocate
105+
assert_raise(RuntimeError) { uninit.dup }
106+
assert_raise(RuntimeError) { uninit.clone }
107+
108+
d = OpenSSL::Digest.new('SHA256')
109+
uninit.send(:initialize_copy, d)
110+
assert_equal d.digest, uninit.digest
111+
end
112+
113+
def test_uninitialized_methods
114+
uninit = OpenSSL::Digest.allocate
115+
assert_raise(RuntimeError) { uninit.digest }
116+
assert_raise(RuntimeError) { uninit.hexdigest }
117+
assert_raise(RuntimeError) { uninit << "data" }
118+
assert_raise(RuntimeError) { uninit.update("data") }
119+
assert_raise(RuntimeError) { uninit.reset }
120+
assert_raise(RuntimeError) { uninit.send(:finish) }
121+
assert_raise(RuntimeError) { uninit.digest_length }
122+
assert_raise(RuntimeError) { uninit.block_length }
123+
end
124+
103125
def test_reset
104126
@d1.update(@data)
105127
dig1 = @d1.digest

‎test/test_hmac.rb‎

Lines changed: 21 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -87,4 +87,25 @@ def test_digest_restrictions
8787
# a key under 112 bits is rejected in approved mode, even with an approved digest
8888
assert_raise(OpenSSL::HMACError) { OpenSSL::HMAC.new('xyz', 'SHA256') }
8989
end
90+
91+
def test_uninitialized_copy
92+
uninit = OpenSSL::HMAC.allocate
93+
assert_instance_of OpenSSL::HMAC, uninit.dup
94+
assert_instance_of OpenSSL::HMAC, uninit.clone
95+
96+
h = OpenSSL::HMAC.new('key', 'SHA256')
97+
h.send(:initialize_copy, uninit)
98+
assert_raise(OpenSSL::HMACError) { h.digest }
99+
end
100+
101+
def test_uninitialized_methods
102+
uninit = OpenSSL::HMAC.allocate
103+
assert_raise(OpenSSL::HMACError) { uninit.digest }
104+
assert_raise(OpenSSL::HMACError) { uninit.hexdigest }
105+
assert_raise(OpenSSL::HMACError) { uninit.inspect }
106+
assert_raise(OpenSSL::HMACError) { uninit.to_s }
107+
assert_raise(OpenSSL::HMACError) { uninit << "data" }
108+
assert_raise(OpenSSL::HMACError) { uninit.update("data") }
109+
assert_raise(OpenSSL::HMACError) { uninit.reset } if defined?(JRUBY_VERSION)
110+
end
90111
end

0 commit comments

Comments
 (0)