From c7b0b650c1467f7f0d7d8d62798c458597be0225 Mon Sep 17 00:00:00 2001 From: Vincent Breitmoser Date: Tue, 30 Dec 2014 00:44:12 +0100 Subject: introduce handling of notation direct key signatures, and experimental pin notation packet --- .../operations/results/OperationResult.java | 4 +- .../keychain/pgp/PgpKeyOperation.java | 49 ++++++++++++++++-- .../keychain/pgp/UncachedKeyRing.java | 59 ++++++++++++++++++---- .../keychain/pgp/WrappedSignature.java | 18 +++++++ OpenKeychain/src/main/res/values-de/strings.xml | 2 +- OpenKeychain/src/main/res/values-es/strings.xml | 2 +- OpenKeychain/src/main/res/values-fr/strings.xml | 2 +- OpenKeychain/src/main/res/values-it/strings.xml | 2 +- OpenKeychain/src/main/res/values-ja/strings.xml | 2 +- OpenKeychain/src/main/res/values-sl/strings.xml | 2 +- OpenKeychain/src/main/res/values-sr/strings.xml | 2 +- OpenKeychain/src/main/res/values-sv/strings.xml | 2 +- OpenKeychain/src/main/res/values/strings.xml | 4 +- 13 files changed, 126 insertions(+), 24 deletions(-) diff --git a/OpenKeychain/src/main/java/org/sufficientlysecure/keychain/operations/results/OperationResult.java b/OpenKeychain/src/main/java/org/sufficientlysecure/keychain/operations/results/OperationResult.java index dc45fabc3..bf14a918b 100644 --- a/OpenKeychain/src/main/java/org/sufficientlysecure/keychain/operations/results/OperationResult.java +++ b/OpenKeychain/src/main/java/org/sufficientlysecure/keychain/operations/results/OperationResult.java @@ -370,13 +370,15 @@ public abstract class OperationResult implements Parcelable { MSG_KC_ERROR_MASTER_ALGO (LogLevel.ERROR, R.string.msg_kc_error_master_algo), MSG_KC_ERROR_DUP_KEY (LogLevel.ERROR, R.string.msg_kc_error_dup_key), MSG_KC_MASTER (LogLevel.DEBUG, R.string.msg_kc_master), + MSG_KC_BAD_TYPE(LogLevel.WARN, R.string.msg_kc_bad_type), MSG_KC_REVOKE_BAD_ERR (LogLevel.WARN, R.string.msg_kc_revoke_bad_err), MSG_KC_REVOKE_BAD_LOCAL (LogLevel.WARN, R.string.msg_kc_revoke_bad_local), MSG_KC_REVOKE_BAD_TIME (LogLevel.WARN, R.string.msg_kc_revoke_bad_time), - MSG_KC_REVOKE_BAD_TYPE (LogLevel.WARN, R.string.msg_kc_revoke_bad_type), MSG_KC_REVOKE_BAD_TYPE_UID (LogLevel.WARN, R.string.msg_kc_revoke_bad_type_uid), MSG_KC_REVOKE_BAD (LogLevel.WARN, R.string.msg_kc_revoke_bad), MSG_KC_REVOKE_DUP (LogLevel.DEBUG, R.string.msg_kc_revoke_dup), + MSG_KC_NOTATION_DUP (LogLevel.DEBUG, R.string.msg_kc_notation_dup), + MSG_KC_NOTATION_EMPTY (LogLevel.DEBUG, R.string.msg_kc_notation_empty), MSG_KC_SUB (LogLevel.DEBUG, R.string.msg_kc_sub), MSG_KC_SUB_BAD(LogLevel.WARN, R.string.msg_kc_sub_bad), MSG_KC_SUB_BAD_ERR(LogLevel.WARN, R.string.msg_kc_sub_bad_err), diff --git a/OpenKeychain/src/main/java/org/sufficientlysecure/keychain/pgp/PgpKeyOperation.java b/OpenKeychain/src/main/java/org/sufficientlysecure/keychain/pgp/PgpKeyOperation.java index c125165a8..08d8164ca 100644 --- a/OpenKeychain/src/main/java/org/sufficientlysecure/keychain/pgp/PgpKeyOperation.java +++ b/OpenKeychain/src/main/java/org/sufficientlysecure/keychain/pgp/PgpKeyOperation.java @@ -34,6 +34,7 @@ import org.spongycastle.openpgp.PGPSecretKeyRing; import org.spongycastle.openpgp.PGPSignature; import org.spongycastle.openpgp.PGPSignatureGenerator; import org.spongycastle.openpgp.PGPSignatureSubpacketGenerator; +import org.spongycastle.openpgp.PGPSignatureSubpacketVector; import org.spongycastle.openpgp.operator.PBESecretKeyDecryptor; import org.spongycastle.openpgp.operator.PBESecretKeyEncryptor; import org.spongycastle.openpgp.operator.PGPContentSignerBuilder; @@ -877,7 +878,8 @@ public class PgpKeyOperation { log.add(LogType.MSG_MF_PASSPHRASE, indent); indent += 1; - sKR = applyNewUnlock(sKR, masterPublicKey, passphrase, saveParcel.mNewUnlock, log, indent); + sKR = applyNewUnlock(sKR, masterPublicKey, masterPrivateKey, + passphrase, saveParcel.mNewUnlock, log, indent); if (sKR == null) { // The error has been logged above, just return a bad state return new EditKeyResult(EditKeyResult.RESULT_ERROR, log, null); @@ -909,19 +911,60 @@ public class PgpKeyOperation { private static PGPSecretKeyRing applyNewUnlock( PGPSecretKeyRing sKR, PGPPublicKey masterPublicKey, + PGPPrivateKey masterPrivateKey, String passphrase, ChangeUnlockParcel newUnlock, OperationLog log, int indent) throws PGPException { if (newUnlock.mNewPassphrase != null) { - return applyNewPassphrase(sKR, masterPublicKey, passphrase, newUnlock.mNewPassphrase, log, indent); + sKR = applyNewPassphrase(sKR, masterPublicKey, passphrase, newUnlock.mNewPassphrase, log, indent); + + // add packet with EMPTY notation data (updates old one, but will be stripped later) + PGPContentSignerBuilder signerBuilder = new JcaPGPContentSignerBuilder( + masterPrivateKey.getPublicKeyPacket().getAlgorithm(), HashAlgorithmTags.SHA512) + .setProvider(Constants.BOUNCY_CASTLE_PROVIDER_NAME); + PGPSignatureGenerator sGen = new PGPSignatureGenerator(signerBuilder); + { // set subpackets + PGPSignatureSubpacketGenerator hashedPacketsGen = new PGPSignatureSubpacketGenerator(); + hashedPacketsGen.setExportable(false, false); + sGen.setHashedSubpackets(hashedPacketsGen.generate()); + } + sGen.init(PGPSignature.DIRECT_KEY, masterPrivateKey); + PGPSignature emptySig = sGen.generateCertification(masterPublicKey); + + masterPublicKey = PGPPublicKey.addCertification(masterPublicKey, emptySig); + PGPSecretKey.replacePublicKey(sKR.getSecretKey(), masterPublicKey); + + return sKR; + } + + if (newUnlock.mNewPin != null) { + sKR = applyNewPassphrase(sKR, masterPublicKey, passphrase, newUnlock.mNewPin, log, indent); + + // add packet with EMPTY notation data (updates old one, but will be stripped later) + PGPContentSignerBuilder signerBuilder = new JcaPGPContentSignerBuilder( + masterPrivateKey.getPublicKeyPacket().getAlgorithm(), HashAlgorithmTags.SHA512) + .setProvider(Constants.BOUNCY_CASTLE_PROVIDER_NAME); + PGPSignatureGenerator sGen = new PGPSignatureGenerator(signerBuilder); + { // set subpackets + PGPSignatureSubpacketGenerator hashedPacketsGen = new PGPSignatureSubpacketGenerator(); + hashedPacketsGen.setExportable(false, false); + hashedPacketsGen.setNotationData(false, false, "pin@unlock.sufficientlysecure.org", "1"); + sGen.setHashedSubpackets(hashedPacketsGen.generate()); + } + sGen.init(PGPSignature.DIRECT_KEY, masterPrivateKey); + PGPSignature emptySig = sGen.generateCertification(masterPublicKey); + + masterPublicKey = PGPPublicKey.addCertification(masterPublicKey, emptySig); + PGPSecretKey.replacePublicKey(sKR.getSecretKey(), masterPublicKey); + + return sKR; } throw new UnsupportedOperationException("PIN passphrases not yet implemented!"); } - private static PGPSecretKeyRing applyNewPassphrase( PGPSecretKeyRing sKR, PGPPublicKey masterPublicKey, diff --git a/OpenKeychain/src/main/java/org/sufficientlysecure/keychain/pgp/UncachedKeyRing.java b/OpenKeychain/src/main/java/org/sufficientlysecure/keychain/pgp/UncachedKeyRing.java index b343c779a..8d1eaa40e 100644 --- a/OpenKeychain/src/main/java/org/sufficientlysecure/keychain/pgp/UncachedKeyRing.java +++ b/OpenKeychain/src/main/java/org/sufficientlysecure/keychain/pgp/UncachedKeyRing.java @@ -41,7 +41,6 @@ import org.sufficientlysecure.keychain.util.IterableIterator; import org.sufficientlysecure.keychain.util.Log; import org.sufficientlysecure.keychain.util.Utf8Util; -import java.io.BufferedInputStream; import java.io.ByteArrayInputStream; import java.io.ByteArrayOutputStream; import java.io.IOException; @@ -302,6 +301,7 @@ public class UncachedKeyRing { PGPPublicKey modified = masterKey; PGPSignature revocation = null; + PGPSignature notation = null; for (PGPSignature zert : new IterableIterator(masterKey.getKeySignatures())) { int type = zert.getSignatureType(); @@ -318,9 +318,9 @@ public class UncachedKeyRing { } WrappedSignature cert = new WrappedSignature(zert); - if (type != PGPSignature.KEY_REVOCATION) { + if (type != PGPSignature.KEY_REVOCATION && type != PGPSignature.DIRECT_KEY) { // Unknown type, just remove - log.add(LogType.MSG_KC_REVOKE_BAD_TYPE, indent, "0x" + Integer.toString(type, 16)); + log.add(LogType.MSG_KC_BAD_TYPE, indent, "0x" + Integer.toString(type, 16)); modified = PGPPublicKey.removeCertification(modified, zert); badCerts += 1; continue; @@ -334,14 +334,6 @@ public class UncachedKeyRing { continue; } - if (cert.isLocal()) { - // Remove revocation certs with "local" flag - log.add(LogType.MSG_KC_REVOKE_BAD_LOCAL, indent); - modified = PGPPublicKey.removeCertification(modified, zert); - badCerts += 1; - continue; - } - try { cert.init(masterKey); if (!cert.verifySignature(masterKey)) { @@ -357,6 +349,41 @@ public class UncachedKeyRing { continue; } + if (cert.isLocal()) { + // Remove revocation certs with "local" flag + log.add(LogType.MSG_KC_REVOKE_BAD_LOCAL, indent); + modified = PGPPublicKey.removeCertification(modified, zert); + badCerts += 1; + continue; + } + + // special case: direct key signatures! + if (cert.getSignatureType() == PGPSignature.DIRECT_KEY) { + // must be local, otherwise strip! + if (!cert.isLocal()) { + log.add(LogType.MSG_KC_BAD_TYPE, indent); + modified = PGPPublicKey.removeCertification(modified, zert); + badCerts += 1; + continue; + } + + // first notation? fine then. + if (notation == null) { + notation = zert; + // more notations? at least one is superfluous, then. + } else if (notation.getCreationTime().before(zert.getCreationTime())) { + log.add(LogType.MSG_KC_NOTATION_DUP, indent); + modified = PGPPublicKey.removeCertification(modified, notation); + redundantCerts += 1; + notation = zert; + } else { + log.add(LogType.MSG_KC_NOTATION_DUP, indent); + modified = PGPPublicKey.removeCertification(modified, zert); + redundantCerts += 1; + } + continue; + } + // first revocation? fine then. if (revocation == null) { revocation = zert; @@ -373,6 +400,16 @@ public class UncachedKeyRing { } } + // If we have a notation packet, check if there is even any data in it? + if (notation != null) { + // If there isn't, might as well strip it + if (new WrappedSignature(notation).getNotation().isEmpty()) { + log.add(LogType.MSG_KC_NOTATION_EMPTY, indent); + modified = PGPPublicKey.removeCertification(modified, notation); + redundantCerts += 1; + } + } + ArrayList processedUserIds = new ArrayList(); for (byte[] rawUserId : new IterableIterator(masterKey.getRawUserIDs())) { String userId = Utf8Util.fromUTF8ByteArrayReplaceBadEncoding(rawUserId); diff --git a/OpenKeychain/src/main/java/org/sufficientlysecure/keychain/pgp/WrappedSignature.java b/OpenKeychain/src/main/java/org/sufficientlysecure/keychain/pgp/WrappedSignature.java index 93afb987a..132a28604 100644 --- a/OpenKeychain/src/main/java/org/sufficientlysecure/keychain/pgp/WrappedSignature.java +++ b/OpenKeychain/src/main/java/org/sufficientlysecure/keychain/pgp/WrappedSignature.java @@ -21,6 +21,7 @@ package org.sufficientlysecure.keychain.pgp; import org.spongycastle.bcpg.SignatureSubpacket; import org.spongycastle.bcpg.SignatureSubpacketTags; import org.spongycastle.bcpg.sig.Exportable; +import org.spongycastle.bcpg.sig.NotationData; import org.spongycastle.bcpg.sig.Revocable; import org.spongycastle.bcpg.sig.RevocationReason; import org.spongycastle.openpgp.PGPException; @@ -37,6 +38,7 @@ import java.io.IOException; import java.security.SignatureException; import java.util.ArrayList; import java.util.Date; +import java.util.HashMap; /** OpenKeychain wrapper around PGPSignature objects. * @@ -239,4 +241,20 @@ public class WrappedSignature { SignatureSubpacket p = mSig.getHashedSubPackets().getSubpacket(SignatureSubpacketTags.EXPORTABLE); return ! ((Exportable) p).isExportable(); } + + public HashMap getNotation() { + HashMap result = new HashMap(); + + // If there is any notation data + if (mSig.getHashedSubPackets() != null + && mSig.getHashedSubPackets().hasSubpacket(SignatureSubpacketTags.NOTATION_DATA)) { + // Iterate over notation data + for (NotationData data : mSig.getHashedSubPackets().getNotationDataOccurrences()) { + result.put(data.getNotationName(), data.getNotationValueBytes()); + } + } + + return result; + } + } diff --git a/OpenKeychain/src/main/res/values-de/strings.xml b/OpenKeychain/src/main/res/values-de/strings.xml index 3bb5eb9bb..ecc3d7d37 100644 --- a/OpenKeychain/src/main/res/values-de/strings.xml +++ b/OpenKeychain/src/main/res/values-de/strings.xml @@ -607,7 +607,7 @@ Entferne fehlerhaftes Schlüsselbund Widerrufszertifikat Entferne Schlüsselbund Widerrufszertifikat mit \"Lokal\" Attribut Entferne Schlüsselbund Widerrufszertifikat mit zukünftigem Zeitstempel - Entferne Hauptschlüsselbeglaubigung unbekannter Art (%s) + Entferne Hauptschlüsselbeglaubigung unbekannter Art (%s) Entferne fehlerhaftes Schlüsselbund Widerrufszertifikat Entferne redundantes Schlüsselbund Widerrufszertifikat Verarbeite Unterschlüssel %s diff --git a/OpenKeychain/src/main/res/values-es/strings.xml b/OpenKeychain/src/main/res/values-es/strings.xml index d95f5bfb4..3de5efb80 100644 --- a/OpenKeychain/src/main/res/values-es/strings.xml +++ b/OpenKeychain/src/main/res/values-es/strings.xml @@ -652,7 +652,7 @@ Eliminando certificado defectuoso de revocación de juego de claves Eliminando certificado de revocación de juego de claves, con distintivo \"local\" Eliminando certificado de revocación de juego de claves, con marca de tiempo futura - Eliminando certificado de clave maestra, de tipo desconocido (%s) + Eliminando certificado de clave maestra, de tipo desconocido (%s) Eliminando certificado de identificación de usuario en posición incorrecta Eliminando certificado defectuoso de revocación de juego de claves Eliminando certificado redundante de revocación de juego de claves diff --git a/OpenKeychain/src/main/res/values-fr/strings.xml b/OpenKeychain/src/main/res/values-fr/strings.xml index d107bb756..ed54f8d16 100644 --- a/OpenKeychain/src/main/res/values-fr/strings.xml +++ b/OpenKeychain/src/main/res/values-fr/strings.xml @@ -652,7 +652,7 @@ Suppression du mauvais certificat de révocation du trousseau Suppression du certificat de révocation du trousseau ayant le drapeau « local » Suppression du certificat de révocation du trousseau ayant une estampille temporelle dans le futur - Suppression du certificat de clef maîtresse de type inconnu (%s) + Suppression du certificat de clef maîtresse de type inconnu (%s) Suppression du certificat de l\'ID d\'utilisateur en mauvaise position Suppression du mauvais certificat de révocation du trousseau Suppression du certificat redondant de révocation du trousseau diff --git a/OpenKeychain/src/main/res/values-it/strings.xml b/OpenKeychain/src/main/res/values-it/strings.xml index ceab689ab..cfe1253e2 100644 --- a/OpenKeychain/src/main/res/values-it/strings.xml +++ b/OpenKeychain/src/main/res/values-it/strings.xml @@ -602,7 +602,7 @@ Permetti accesso?\n\nATTENZIONE: Se non sai perche\' questo schermata e\' appars Rimozione di certificato di revoca del portachiavi corrotto Rimozione certificato di revoca del portachiavi con caratteristica \"locale\" Rimozione certificato di revoca del portachiavi con marca temporale futura - Rimozione certificato della chiave principale di tipo sconosciuto (%s) + Rimozione certificato della chiave principale di tipo sconosciuto (%s) Rimozione certificato di revoca del portachiavi corrotto Rimozione certificato di revoca del portachiavi ridondante Elaborazione sottochiave %s diff --git a/OpenKeychain/src/main/res/values-ja/strings.xml b/OpenKeychain/src/main/res/values-ja/strings.xml index 607dfa833..a4e1d4275 100644 --- a/OpenKeychain/src/main/res/values-ja/strings.xml +++ b/OpenKeychain/src/main/res/values-ja/strings.xml @@ -618,7 +618,7 @@ 問題のある鍵輪の破棄証明を破棄中 鍵輪のローカルフラグ付き破棄証明を破棄中 鍵輪の未来にタイムスタンプがある破棄証明を破棄中 - 問題のある主鍵の不明な型 (%s) の証明を破棄中 + 問題のある主鍵の不明な型 (%s) の証明を破棄中 不正な位置のユーザID検証を破棄中 問題のある鍵輪の破棄証明を破棄中 重複している鍵輪の破棄証明を破棄中 diff --git a/OpenKeychain/src/main/res/values-sl/strings.xml b/OpenKeychain/src/main/res/values-sl/strings.xml index c99b24d79..c30fd87b5 100644 --- a/OpenKeychain/src/main/res/values-sl/strings.xml +++ b/OpenKeychain/src/main/res/values-sl/strings.xml @@ -450,7 +450,7 @@ Umikam slab certifikat za preklic zbirk ključev Umikam certifikat za preklic zbirk ključev z oznako \"lokalno\" Umikam certifikat za preklic zbirk ključev s časovno znamko v prihodnosti - Umikam certifikat glavnega ključa neznanega tipa (%s) + Umikam certifikat glavnega ključa neznanega tipa (%s) Umikam slab certifikat za preklic zbirk ključev Umikam odvečen certifikat za preklic zbirk ključev Obdelujem podključ %s diff --git a/OpenKeychain/src/main/res/values-sr/strings.xml b/OpenKeychain/src/main/res/values-sr/strings.xml index ff50a637b..31ed39440 100644 --- a/OpenKeychain/src/main/res/values-sr/strings.xml +++ b/OpenKeychain/src/main/res/values-sr/strings.xml @@ -672,7 +672,7 @@ Уклањам лош сертификат опозива привеска Уклањам сертификат опозива привеска са заставицом „локални“ Уклањам сертификат опозива привеска са временском ознаком у будућности - Уклањам сертификат главног кључа непознатог типа (%s) + Уклањам сертификат главног кључа непознатог типа (%s) Уклањам сертификат корисничког ИД-а са погрешног места Уклањам лош сертификат опозива привеска Уклањам сувишни сертификат опозива привеска diff --git a/OpenKeychain/src/main/res/values-sv/strings.xml b/OpenKeychain/src/main/res/values-sv/strings.xml index a56eb7f75..c76c6c356 100644 --- a/OpenKeychain/src/main/res/values-sv/strings.xml +++ b/OpenKeychain/src/main/res/values-sv/strings.xml @@ -573,7 +573,7 @@ Bearbetar huvudnyckel Tar bort dåligt återkallelsecertifikat för nyckelring Tar bort återkallelsecertifikat för nyckelring med framtida tidstämpel - Tar bort huvudnyckelcertifikat av okänd typ (%s) + Tar bort huvudnyckelcertifikat av okänd typ (%s) Tar bort dåligt återkallelsecertifikat för nyckelring Tar bort överflödigt återkallelsecertifikat för nyckelring Bearbetar undernyckel %s diff --git a/OpenKeychain/src/main/res/values/strings.xml b/OpenKeychain/src/main/res/values/strings.xml index 9ea16a0ab..52c75109a 100644 --- a/OpenKeychain/src/main/res/values/strings.xml +++ b/OpenKeychain/src/main/res/values/strings.xml @@ -709,13 +709,15 @@ "The master key uses an unknown (%s) algorithm!" "Subkey %s occurs twice in keyring. Keyring is malformed, not importing!" "Processing master key" + "Removing master key certificate of unknown type (%s)" "Removing bad keyring revocation certificate" "Removing keyring revocation certificate with "local" flag" "Removing keyring revocation certificate with future timestamp" - "Removing master key certificate of unknown type (%s)" "Removing user ID certificate in bad position" "Removing bad keyring revocation certificate" "Removing redundant keyring revocation certificate" + "Removing redundant notation certificate" + "Removing empty notation certificate" "Processing subkey %s" "Removing invalid subkey binding certificate" "Removing bad subkey binding certificate" -- cgit v1.2.3