/* * Copyright (C) 2014 Dominik Schürmann <dominik@dominikschuermann.de> * * 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 <http://www.gnu.org/licenses/>. */ package org.sufficientlysecure.keychain.pgp; import java.util.ArrayList; import java.util.Collections; import java.util.Date; import java.util.List; import org.openintents.openpgp.OpenPgpSignatureResult; import org.openintents.openpgp.OpenPgpSignatureResult.SenderStatusResult; import org.openintents.openpgp.util.OpenPgpUtils; import org.openintents.openpgp.util.OpenPgpUtils.UserId; import org.sufficientlysecure.keychain.Constants; import org.sufficientlysecure.keychain.pgp.exception.PgpKeyNotFoundException; import org.sufficientlysecure.keychain.provider.KeyRepository; import org.sufficientlysecure.keychain.provider.KeyRepository.NotFoundException; import org.sufficientlysecure.keychain.util.Log; /** * This class can be used to build OpenPgpSignatureResult objects based on several checks. * It serves as a constraint which information are returned inside an OpenPgpSignatureResult object. */ public class OpenPgpSignatureResultBuilder { // injected private final KeyRepository mKeyRepository; // OpenPgpSignatureResult private String mPrimaryUserId; private ArrayList<String> mUserIds = new ArrayList<>(); private ArrayList<String> mConfirmedUserIds; private long mKeyId; private SenderStatusResult mSenderStatusResult; // builder private boolean mSignatureAvailable = false; private boolean mKnownKey = false; private boolean mValidSignature = false; private boolean mIsSignatureKeyCertified = false; private boolean mIsKeyRevoked = false; private boolean mIsKeyExpired = false; private String mSenderAddress; private Date mSignatureTimestamp; private ArrayList<SecurityProblem> mSecurityProblems; public OpenPgpSignatureResultBuilder(KeyRepository keyRepository) { this.mKeyRepository = keyRepository; } public void setPrimaryUserId(String userId) { this.mPrimaryUserId = userId; } public void setKeyId(long keyId) { this.mKeyId = keyId; } public void setSignatureTimestamp(Date signatureTimestamp) { mSignatureTimestamp = signatureTimestamp; } public void setKnownKey(boolean knownKey) { this.mKnownKey = knownKey; } public void setValidSignature(boolean validSignature) { this.mValidSignature = validSignature; } public void addSecurityProblem(SecurityProblem securityProblem) { if (mSecurityProblems == null) { mSecurityProblems = new ArrayList<>(); } mSecurityProblems.add(securityProblem); } public List<SecurityProblem> getSecurityProblems() { return mSecurityProblems != null ? Collections.unmodifiableList(mSecurityProblems) : null; } public void setSignatureKeyCertified(boolean isSignatureKeyCertified) { this.mIsSignatureKeyCertified = isSignatureKeyCertified; } public void setSignatureAvailable(boolean signatureAvailable) { this.mSignatureAvailable = signatureAvailable; } public void setKeyRevoked(boolean keyRevoked) { this.mIsKeyRevoked = keyRevoked; } public void setKeyExpired(boolean keyExpired) { this.mIsKeyExpired = keyExpired; } public void setUserIds(ArrayList<String> userIds, ArrayList<String> confirmedUserIds) { this.mUserIds = userIds; this.mConfirmedUserIds = confirmedUserIds; } public void initValid(CanonicalizedPublicKey signingKey) { setSignatureAvailable(true); setKnownKey(true); CanonicalizedKeyRing signingRing = signingKey.getKeyRing(); // from RING setKeyId(signingRing.getMasterKeyId()); try { setPrimaryUserId(signingRing.getPrimaryUserIdWithFallback()); } catch (PgpKeyNotFoundException e) { Log.d(Constants.TAG, "No primary user id in keyring with master key id " + signingRing.getMasterKeyId()); } setSignatureKeyCertified(signingRing.getVerified() > 0); try { ArrayList<String> allUserIds = signingRing.getUnorderedUserIds(); ArrayList<String> confirmedUserIds = mKeyRepository.getConfirmedUserIds(signingRing.getMasterKeyId()); setUserIds(allUserIds, confirmedUserIds); if (mSenderAddress != null) { if (userIdListContainsAddress(mSenderAddress, confirmedUserIds)) { mSenderStatusResult = SenderStatusResult.USER_ID_CONFIRMED; } else if (userIdListContainsAddress(mSenderAddress, allUserIds)) { mSenderStatusResult = SenderStatusResult.USER_ID_UNCONFIRMED; } else { mSenderStatusResult = SenderStatusResult.USER_ID_MISSING; } } else { mSenderStatusResult = SenderStatusResult.UNKNOWN; } } catch (NotFoundException e) { throw new IllegalStateException("Key didn't exist anymore for user id query!", e); } // either master key is expired/revoked or this specific subkey is expired/revoked setKeyExpired(signingRing.isExpired() || signingKey.isExpired()); setKeyRevoked(signingRing.isRevoked() || signingKey.isRevoked()); } private static boolean userIdListContainsAddress(String senderAddress, ArrayList<String> confirmedUserIds) { for (String rawUserId : confirmedUserIds) { UserId userId = OpenPgpUtils.splitUserId(rawUserId); if (senderAddress.equalsIgnoreCase(userId.email)) { return true; } } return false; } public OpenPgpSignatureResult build() { if (!mSignatureAvailable) { Log.d(Constants.TAG, "RESULT_NO_SIGNATURE"); return OpenPgpSignatureResult.createWithNoSignature(); } if (!mKnownKey) { Log.d(Constants.TAG, "RESULT_KEY_MISSING"); return OpenPgpSignatureResult.createWithKeyMissing(mKeyId, mSignatureTimestamp); } if (!mValidSignature) { Log.d(Constants.TAG, "RESULT_INVALID_SIGNATURE"); return OpenPgpSignatureResult.createWithInvalidSignature(); } int signatureStatus; if (mIsKeyRevoked) { Log.d(Constants.TAG, "RESULT_INVALID_KEY_REVOKED"); signatureStatus = OpenPgpSignatureResult.RESULT_INVALID_KEY_REVOKED; } else if (mIsKeyExpired) { Log.d(Constants.TAG, "RESULT_INVALID_KEY_EXPIRED"); signatureStatus = OpenPgpSignatureResult.RESULT_INVALID_KEY_EXPIRED; } else if (mSecurityProblems != null && !mSecurityProblems.isEmpty()) { Log.d(Constants.TAG, "RESULT_INVALID_INSECURE"); signatureStatus = OpenPgpSignatureResult.RESULT_INVALID_KEY_INSECURE; } else if (mIsSignatureKeyCertified) { Log.d(Constants.TAG, "RESULT_VALID_CONFIRMED"); signatureStatus = OpenPgpSignatureResult.RESULT_VALID_KEY_CONFIRMED; } else { Log.d(Constants.TAG, "RESULT_VALID_UNCONFIRMED"); signatureStatus = OpenPgpSignatureResult.RESULT_VALID_KEY_UNCONFIRMED; } return OpenPgpSignatureResult.createWithValidSignature( signatureStatus, mPrimaryUserId, mKeyId, mUserIds, mConfirmedUserIds, mSenderStatusResult, mSignatureTimestamp); } public void setSenderAddress(String senderAddress) { mSenderAddress = senderAddress; } }