From: Felix Dörre Date: Tue, 29 Jul 2014 17:36:13 +0000 (+0200) Subject: Add class for parsing (and writing) SPKAC. With testcase. X-Git-Url: https://code.wpia.club/?p=gigi.git;a=commitdiff_plain;h=affab50c29de5e66ea1f44189a809093c136d1c0 Add class for parsing (and writing) SPKAC. With testcase. --- diff --git a/src/org/cacert/gigi/crypto/SPKAC.java b/src/org/cacert/gigi/crypto/SPKAC.java new file mode 100644 index 00000000..75e59d19 --- /dev/null +++ b/src/org/cacert/gigi/crypto/SPKAC.java @@ -0,0 +1,103 @@ +package org.cacert.gigi.crypto; + +import java.io.IOException; +import java.security.GeneralSecurityException; +import java.security.Signature; +import java.security.SignatureException; +import sun.security.util.DerInputStream; +import sun.security.util.DerOutputStream; +import sun.security.util.DerValue; +import sun.security.x509.AlgorithmId; +import sun.security.x509.X509Key; + +/** + * This class handles a SPKAC. A SPKAC has the following structure; + * + *
+ * PublicKeyAndChallenge ::= SEQUENCE {
+ *     spki SubjectPublicKeyInfo,
+ *     challenge IA5STRING
+ * }
+ * 
+ * SignedPublicKeyAndChallenge ::= SEQUENCE {
+ *     publicKeyAndChallenge PublicKeyAndChallenge,
+ *     signatureAlgorithm AlgorithmIdentifier,
+ *     signature BIT STRING
+ * }
+ * 
+ */ +public class SPKAC { + + private X509Key pubkey; + + private String challenge; + + public SPKAC(byte[] data) throws IOException, GeneralSecurityException { + DerInputStream derIn = new DerInputStream(data); + + DerValue derSPKACContent[] = derIn.getSequence(3); + if (derIn.available() != 0) { + throw new IllegalArgumentException("Additional data after SPKAC."); + } + + AlgorithmId id = AlgorithmId.parse(derSPKACContent[1]); + + derIn = derSPKACContent[0].toDerInputStream(); + + pubkey = (X509Key) X509Key.parse(derIn.getDerValue()); + + DerValue derChallenge = derIn.getDerValue(); + if (derIn.available() != 0) { + throw new IllegalArgumentException("Additional data after SPKAC."); + } + if (derChallenge.length() != 0) { + challenge = derChallenge.getIA5String(); + } + + Signature s = Signature.getInstance(id.getName()); + s.initVerify(pubkey); + s.update(derSPKACContent[0].toByteArray()); + byte[] signature = derSPKACContent[2].getBitString(); + if ( !s.verify(signature)) { + throw new SignatureException(); + } + + } + + public String getChallenge() { + return challenge; + } + + public X509Key getPubkey() { + return pubkey; + } + + public SPKAC(X509Key pubkey, String challange) { + this.pubkey = pubkey; + challenge = challange; + } + + public byte[] getEncoded(Signature sign) throws GeneralSecurityException, IOException { + DerOutputStream SPKAC = new DerOutputStream(); + DerOutputStream SPKI = new DerOutputStream(); + + pubkey.encode(SPKI); + SPKI.putIA5String(challenge); + + SPKAC.write(DerValue.tag_Sequence, SPKI); + byte[] toSign = SPKAC.toByteArray(); + SPKI.close(); + + AlgorithmId aid = AlgorithmId.get(sign.getAlgorithm()); + aid.encode(SPKAC); + sign.update(toSign); + SPKAC.putBitString(sign.sign()); + + DerOutputStream res = new DerOutputStream(); + res.write(DerValue.tag_Sequence, SPKAC); + SPKAC.close(); + byte[] result = res.toByteArray(); + res.close(); + return result; + } +} diff --git a/tests/org/cacert/gigi/crypto/TestSPKAC.java b/tests/org/cacert/gigi/crypto/TestSPKAC.java new file mode 100644 index 00000000..9f022045 --- /dev/null +++ b/tests/org/cacert/gigi/crypto/TestSPKAC.java @@ -0,0 +1,72 @@ +package org.cacert.gigi.crypto; + +import static org.junit.Assert.*; + +import java.io.IOException; +import java.io.InputStreamReader; +import java.security.GeneralSecurityException; +import java.security.KeyPair; +import java.security.KeyPairGenerator; +import java.security.Signature; +import java.security.SignatureException; +import java.security.interfaces.RSAKey; +import java.util.Base64; + +import org.cacert.gigi.testUtils.IOUtils; +import org.junit.Test; + +import sun.security.x509.X509Key; + +public class TestSPKAC { + + @Test + public void testParse() throws GeneralSecurityException, IOException { + String spkac = IOUtils.readURL(new InputStreamReader(TestSPKAC.class.getResourceAsStream("sampleSPKAC.txt"))); + SPKAC parsed = new SPKAC(Base64.getDecoder().decode(spkac.replaceAll("[\r\n]", ""))); + assertEquals("i am in the testcase", parsed.getChallenge()); + RSAKey k = ((RSAKey) parsed.getPubkey()); + assertEquals("a4004c2addf204fb26ce98f5963cc76def609ec0c50905e091fb84e986e3cb" + // + "0d5e14edb9cb8e10524350bd2351589284a4f631ddf9b87f04ea0e58f7d8d816b58" + // + "d052ce08b6576c04a7d45daf25b0ac9306f9cbb1f626e4ac301b7a4a3a062252b9a" + // + "472b2cde5ec803407b18879a59ccba7716016b1de4537a005b2bd0fd6071", k.getModulus().toString(16)); + } + + @Test + public void testAddData() throws GeneralSecurityException, IOException { + String spkac = IOUtils.readURL(new InputStreamReader(TestSPKAC.class.getResourceAsStream("sampleSPKAC.txt"))); + byte[] data = Base64.getDecoder().decode(spkac.replaceAll("[\r\n]", "")); + byte[] tampered = new byte[data.length + 1]; + System.arraycopy(data, 0, tampered, 0, data.length); + try { + new SPKAC(tampered); + fail("Expected illegal arg exception."); + } catch (IllegalArgumentException e) { + // expected + } + // change the last byte of the signature. + data[data.length - 1]--; + try { + new SPKAC(data); + fail("Expected SignatureException."); + } catch (SignatureException e) { + // expected + } + } + + @Test + public void testGen() throws GeneralSecurityException, IOException { + KeyPairGenerator pkg = KeyPairGenerator.getInstance("RSA"); + pkg.initialize(1024); + KeyPair kp = pkg.generateKeyPair(); + + SPKAC s = new SPKAC((X509Key) kp.getPublic(), "this is a even bigger challange"); + Signature sign = Signature.getInstance("SHA512withRSA"); + sign.initSign(kp.getPrivate()); + + byte[] res = s.getEncoded(sign); + SPKAC parsed = new SPKAC(res); + assertEquals(s.getChallenge(), parsed.getChallenge()); + assertEquals(s.getPubkey(), parsed.getPubkey()); + + } +} diff --git a/tests/org/cacert/gigi/crypto/sampleSPKAC.txt b/tests/org/cacert/gigi/crypto/sampleSPKAC.txt new file mode 100644 index 00000000..b3f44b67 --- /dev/null +++ b/tests/org/cacert/gigi/crypto/sampleSPKAC.txt @@ -0,0 +1,8 @@ +MIIBTjCBuDCBnzANBgkqhkiG9w0BAQEFAAOBjQAwgYkCgYEApABMKt3yBPsmzpj +1ljzHbe9gnsDFCQXgkfuE6Ybjyw1eFO25y44QUkNQvSNRWJKEpPYx3fm4fwTqDl +j32NgWtY0FLOCLZXbASn1F2vJbCskwb5y7H2JuSsMBt6SjoGIlK5pHKyzeXsgDQ +HsYh5pZzLp3FgFrHeRTegBbK9D9YHECAwEAARYUaSBhbSBpbiB0aGUgdGVzdGNh +c2UwDQYJKoZIhvcNAQEEBQADgYEAamIuLgSIgEfy5VSp+0R2wCtmxVvX9mIEhVg +kbnNjC1bNJdtM3HPVlYbPRKuSaucgF4A/pPX55l6JECsIu6yGIyAszwGc1+rspg +zEztsuU38IOl0sdxZBujyv2v1eoMB6TzBlsJ2hb/pC8XlmrCa5g6n1hI6XLgdu6 +3tyT4lBQ6E=