Skip to content

Commit b81798e

Browse files
committed
[feat] implement Netscape::SPKI#to_text
1 parent 13e7022 commit b81798e

3 files changed

Lines changed: 92 additions & 3 deletions

File tree

src/main/java/org/jruby/ext/openssl/NetscapeSPKI.java

Lines changed: 58 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -45,6 +45,7 @@
4545
import org.jruby.RubyClass;
4646
import org.jruby.RubyModule;
4747
import org.jruby.RubyObject;
48+
import org.jruby.RubyString;
4849
import org.jruby.anno.JRubyMethod;
4950
import org.jruby.exceptions.RaiseException;
5051
import org.jruby.ext.openssl.impl.Base64;
@@ -163,9 +164,63 @@ private byte[] toDER() throws IOException {
163164
}
164165

165166
@JRubyMethod
166-
public IRubyObject to_text() {
167-
warn(getRuntime().getCurrentContext(), "WARNING: unimplemented method called: Netscape::SPKI#to_text");
168-
return getRuntime().getNil();
167+
public IRubyObject to_text(ThreadContext context) {
168+
final Ruby runtime = context.runtime;
169+
170+
final StringBuilder text = new StringBuilder(256);
171+
text.append("Netscape SPKI:\n");
172+
173+
final NetscapeCertRequest cert = (NetscapeCertRequest) this.cert;
174+
if (cert == null) return StringHelper.newString(runtime, text);
175+
176+
// public key algorithm
177+
final AlgorithmIdentifier keyAlg = cert.getKeyAlgorithm();
178+
final String keyAlgName = resolveAlgorithmName(runtime, keyAlg);
179+
text.append(" Public Key Algorithm: ").append(keyAlgName).append('\n');
180+
181+
if (public_key instanceof PKey) {
182+
try {
183+
final RubyString keyText = ((PKey) public_key).to_text();
184+
for (CharSequence line : StringHelper.split(keyText, '\n')) {
185+
text.append(" ").append(line).append('\n');
186+
}
187+
} catch (Exception e) {
188+
text.append(" Unable to load public key\n");
189+
}
190+
}
191+
192+
final String challenge = cert.getChallenge();
193+
if (challenge != null && !challenge.isEmpty()) {
194+
text.append(" Challenge String: ").append(challenge).append('\n');
195+
}
196+
197+
final AlgorithmIdentifier sigAlg = cert.getSigningAlgorithm();
198+
final String sigAlgName = resolveAlgorithmName(runtime, sigAlg);
199+
text.append(" Signature Algorithm: ").append(sigAlgName);
200+
201+
// signature bytes as hex with : separators, 18 bytes per line
202+
final byte[] sig = cert.getSignatureBits();
203+
if (sig != null) {
204+
for (int i = 0; i < sig.length; i++) {
205+
if (i % 18 == 0) text.append("\n ");
206+
text.append(String.format("%02x", sig[i] & 0xFF));
207+
if (i + 1 < sig.length) text.append(':');
208+
}
209+
}
210+
text.append('\n');
211+
212+
return StringHelper.newString(runtime, text);
213+
}
214+
215+
private static String resolveAlgorithmName(final Ruby runtime, final AlgorithmIdentifier algId) {
216+
if (algId == null) return null;
217+
try {
218+
final String name = ASN1.oid2name(runtime, algId.getAlgorithm(), true);
219+
if (name != null) return name;
220+
} catch (RuntimeException e) {
221+
debug("Failed to resolve algorithm name: " + algId, e);
222+
}
223+
return algId.getAlgorithm().getId();
169224
}
170225

171226
@JRubyMethod

src/main/java/org/jruby/ext/openssl/impl/NetscapeCertRequest.java

Lines changed: 5 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -202,6 +202,11 @@ public void setKeyAlgorithm(AlgorithmIdentifier value)
202202
keyAlg = value;
203203
}
204204

205+
public byte[] getSignatureBits()
206+
{
207+
return signatureBits;
208+
}
209+
205210
public PublicKey getPublicKey()
206211
{
207212
return publicKey;

src/test/ruby/test_ns_spki.rb

Lines changed: 29 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,29 @@
1+
require File.expand_path('test_helper', File.dirname(__FILE__))
2+
3+
class TestNSSPKI < TestCase
4+
# from the Netscape SPKI specification
5+
B64 = 'MIHFMHEwXDANBgkqhkiG9w0BAQEFAANLADBIAkEAnX0TILJrOMUue+PtwBRE6XfV' \
6+
'WtKQbsshxk5ZhcUwcwyvcnIq9b82QhJdoACdD34rqfCAIND46fXKQUnb0mvKzQID' \
7+
'AQABFhFNb3ppbGxhSXNNeUZyaWVuZDANBgkqhkiG9w0BAQQFAANBAAKv2Eex2n/S' \
8+
'r/7iJNroWlSzSMtTiQTEB+ADWHGj9u1xrUrOilq/o2cuQxIfZcNZkYAkWP4DubqW' \
9+
'i0//rgBvmco='
10+
11+
def test_decode_data
12+
spki = OpenSSL::Netscape::SPKI.new(B64)
13+
assert_equal 'MozillaIsMyFriend', spki.challenge
14+
assert_instance_of OpenSSL::PKey::RSA, spki.public_key
15+
end
16+
17+
def test_to_text
18+
spki = OpenSSL::Netscape::SPKI.new(B64)
19+
text = spki.to_text
20+
21+
assert_not_nil text, 'to_text should not return nil'
22+
assert_match(/\ANetscape SPKI:\n/, text)
23+
assert_match(/Public Key Algorithm: /, text)
24+
assert_match(/Challenge String: MozillaIsMyFriend/, text)
25+
assert_match(/Signature Algorithm: /, text)
26+
# signature hex bytes with : separators
27+
assert_match(/[0-9a-f]{2}(:[0-9a-f]{2})+/, text)
28+
end
29+
end

0 commit comments

Comments
 (0)