From 56af349cf4e0e763088dd2b8869d6ac3e95ec43c Mon Sep 17 00:00:00 2001 From: Vincent Breitmoser Date: Tue, 13 Feb 2018 18:25:00 +0100 Subject: [PATCH] add support for EdDSA on security tokens (currently only gnuk) --- .../securitytoken/EdDSAKeyFormat.java | 41 +++++++++++++++++++ .../keychain/securitytoken/KeyFormat.java | 7 +++- .../SecurityTokenPsoSignTokenOp.java | 11 +++-- .../keychain/ArmoredInputStreamTest.java | 1 + 4 files changed, 55 insertions(+), 5 deletions(-) create mode 100644 OpenKeychain/src/main/java/org/sufficientlysecure/keychain/securitytoken/EdDSAKeyFormat.java diff --git a/OpenKeychain/src/main/java/org/sufficientlysecure/keychain/securitytoken/EdDSAKeyFormat.java b/OpenKeychain/src/main/java/org/sufficientlysecure/keychain/securitytoken/EdDSAKeyFormat.java new file mode 100644 index 000000000..1ed413651 --- /dev/null +++ b/OpenKeychain/src/main/java/org/sufficientlysecure/keychain/securitytoken/EdDSAKeyFormat.java @@ -0,0 +1,41 @@ +/* + * Copyright (C) 2017 Schürmann & Breitmoser GbR + * + * This program is free software: you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation, either version 3 of the License, or + * (at your option) any later version. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program. If not, see . + */ + +package org.sufficientlysecure.keychain.securitytoken; + +import org.bouncycastle.asn1.ASN1ObjectIdentifier; +import org.bouncycastle.asn1.nist.NISTNamedCurves; +import org.bouncycastle.asn1.x9.X9ECParameters; +import org.bouncycastle.bcpg.sig.KeyFlags; +import org.bouncycastle.math.ec.ECCurve; +import org.sufficientlysecure.keychain.service.SaveKeyringParcel; +import org.sufficientlysecure.keychain.service.SaveKeyringParcel.SubkeyAdd; + + +// 4.3.3.6 Algorithm Attributes +public class EdDSAKeyFormat extends KeyFormat { + + public EdDSAKeyFormat() { + super(KeyFormatType.EdDSAKeyFormatType); + } + + @Override + public void addToSaveKeyringParcel(SaveKeyringParcel.Builder builder, int keyFlags) { + builder.addSubkeyAdd(SubkeyAdd.createSubkeyAdd(SaveKeyringParcel.Algorithm.EDDSA, + null, null, keyFlags, 0L)); + } +} diff --git a/OpenKeychain/src/main/java/org/sufficientlysecure/keychain/securitytoken/KeyFormat.java b/OpenKeychain/src/main/java/org/sufficientlysecure/keychain/securitytoken/KeyFormat.java index a1b00397a..fe043cd07 100644 --- a/OpenKeychain/src/main/java/org/sufficientlysecure/keychain/securitytoken/KeyFormat.java +++ b/OpenKeychain/src/main/java/org/sufficientlysecure/keychain/securitytoken/KeyFormat.java @@ -27,7 +27,8 @@ public abstract class KeyFormat { public enum KeyFormatType { RSAKeyFormatType, - ECKeyFormatType + ECKeyFormatType, + EdDSAKeyFormatType } private final KeyFormatType mKeyFormatType; @@ -53,7 +54,7 @@ public abstract class KeyFormat { case PublicKeyAlgorithmTags.ECDH: case PublicKeyAlgorithmTags.ECDSA: if (bytes.length < 2) { - throw new IllegalArgumentException("Bad length for RSA attributes"); + throw new IllegalArgumentException("Bad length for EC attributes"); } int len = bytes.length - 1; if (bytes[bytes.length - 1] == (byte)0xff) { @@ -65,6 +66,8 @@ public abstract class KeyFormat { System.arraycopy(bytes, 1, boid, 2, len); final ASN1ObjectIdentifier oid = ASN1ObjectIdentifier.getInstance(boid); return new ECKeyFormat(oid, ECKeyFormat.ECAlgorithmFormat.from(bytes[0], bytes[bytes.length - 1])); + case PublicKeyAlgorithmTags.EDDSA: + return new EdDSAKeyFormat(); default: throw new IllegalArgumentException("Unsupported Algorithm id " + bytes[0]); diff --git a/OpenKeychain/src/main/java/org/sufficientlysecure/keychain/securitytoken/operations/SecurityTokenPsoSignTokenOp.java b/OpenKeychain/src/main/java/org/sufficientlysecure/keychain/securitytoken/operations/SecurityTokenPsoSignTokenOp.java index 7a0332f41..1f0907970 100644 --- a/OpenKeychain/src/main/java/org/sufficientlysecure/keychain/securitytoken/operations/SecurityTokenPsoSignTokenOp.java +++ b/OpenKeychain/src/main/java/org/sufficientlysecure/keychain/securitytoken/operations/SecurityTokenPsoSignTokenOp.java @@ -108,6 +108,7 @@ public class SecurityTokenPsoSignTokenOp { data = prepareDsi(hash, hashAlgo); break; case ECKeyFormatType: + case EdDSAKeyFormatType: data = hash; break; default: @@ -128,7 +129,7 @@ public class SecurityTokenPsoSignTokenOp { } break; - case ECKeyFormatType: + case ECKeyFormatType: { // "plain" encoding, see https://github.com/open-keychain/open-keychain/issues/2108 if (signature.length % 2 != 0) { throw new IOException("Bad signature length!"); @@ -142,8 +143,12 @@ public class SecurityTokenPsoSignTokenOp { final ByteArrayOutputStream baos = new ByteArrayOutputStream(); ASN1OutputStream out = new ASN1OutputStream(baos); out.writeObject(new DERSequence(new ASN1Encodable[] { new ASN1Integer(br), new ASN1Integer(bs) })); - out.flush(); - signature = baos.toByteArray(); + out.flush(); + signature = baos.toByteArray(); + break; + } + + case EdDSAKeyFormatType: break; } return signature; diff --git a/OpenKeychain/src/test/java/org/sufficientlysecure/keychain/ArmoredInputStreamTest.java b/OpenKeychain/src/test/java/org/sufficientlysecure/keychain/ArmoredInputStreamTest.java index 57452d64b..a4d95f02e 100644 --- a/OpenKeychain/src/test/java/org/sufficientlysecure/keychain/ArmoredInputStreamTest.java +++ b/OpenKeychain/src/test/java/org/sufficientlysecure/keychain/ArmoredInputStreamTest.java @@ -4,6 +4,7 @@ package org.sufficientlysecure.keychain; import java.io.InputStream; import org.bouncycastle.bcpg.ArmoredInputStream; +import org.bouncycastle.util.encoders.Hex; import org.junit.Test; import org.junit.runner.RunWith; import org.sufficientlysecure.keychain.pgp.UncachedKeyringTest;