]> WPIA git - gigi.git/commitdiff
Add class for parsing (and writing) SPKAC. With testcase.
authorFelix Dörre <felix@dogcraft.de>
Tue, 29 Jul 2014 17:36:13 +0000 (19:36 +0200)
committerFelix Dörre <felix@dogcraft.de>
Tue, 29 Jul 2014 17:36:13 +0000 (19:36 +0200)
src/org/cacert/gigi/crypto/SPKAC.java [new file with mode: 0644]
tests/org/cacert/gigi/crypto/TestSPKAC.java [new file with mode: 0644]
tests/org/cacert/gigi/crypto/sampleSPKAC.txt [new file with mode: 0644]

diff --git a/src/org/cacert/gigi/crypto/SPKAC.java b/src/org/cacert/gigi/crypto/SPKAC.java
new file mode 100644 (file)
index 0000000..75e59d1
--- /dev/null
@@ -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;
+ * 
+ * <pre>
+ * PublicKeyAndChallenge ::= SEQUENCE {
+ *     spki SubjectPublicKeyInfo,
+ *     challenge IA5STRING
+ * }
+ * 
+ * SignedPublicKeyAndChallenge ::= SEQUENCE {
+ *     publicKeyAndChallenge PublicKeyAndChallenge,
+ *     signatureAlgorithm AlgorithmIdentifier,
+ *     signature BIT STRING
+ * }
+ * </pre>
+ */
+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 (file)
index 0000000..9f02204
--- /dev/null
@@ -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 (file)
index 0000000..b3f44b6
--- /dev/null
@@ -0,0 +1,8 @@
+MIIBTjCBuDCBnzANBgkqhkiG9w0BAQEFAAOBjQAwgYkCgYEApABMKt3yBPsmzpj
+1ljzHbe9gnsDFCQXgkfuE6Ybjyw1eFO25y44QUkNQvSNRWJKEpPYx3fm4fwTqDl
+j32NgWtY0FLOCLZXbASn1F2vJbCskwb5y7H2JuSsMBt6SjoGIlK5pHKyzeXsgDQ
+HsYh5pZzLp3FgFrHeRTegBbK9D9YHECAwEAARYUaSBhbSBpbiB0aGUgdGVzdGNh
+c2UwDQYJKoZIhvcNAQEEBQADgYEAamIuLgSIgEfy5VSp+0R2wCtmxVvX9mIEhVg
+kbnNjC1bNJdtM3HPVlYbPRKuSaucgF4A/pPX55l6JECsIu6yGIyAszwGc1+rspg
+zEztsuU38IOl0sdxZBujyv2v1eoMB6TzBlsJ2hb/pC8XlmrCa5g6n1hI6XLgdu6
+3tyT4lBQ6E=