Move pgp classes into subpackage

This commit is contained in:
Dominik Schürmann
2013-09-15 15:29:38 +02:00
parent e6801ec951
commit 121f8aaca0
27 changed files with 41 additions and 43 deletions

View File

@@ -0,0 +1,139 @@
/*
* Copyright (C) 2012-2013 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.io.ByteArrayOutputStream;
import java.io.IOException;
import java.util.ArrayList;
import java.util.Iterator;
import org.spongycastle.openpgp.PGPKeyRing;
import org.spongycastle.openpgp.PGPObjectFactory;
import org.spongycastle.openpgp.PGPSecretKey;
import org.spongycastle.openpgp.PGPSecretKeyRing;
import org.sufficientlysecure.keychain.Constants;
import org.sufficientlysecure.keychain.util.Log;
public class PgpConversionHelper {
/**
* Convert from byte[] to PGPKeyRing
*
* @param keysBytes
* @return
*/
public static PGPKeyRing BytesToPGPKeyRing(byte[] keysBytes) {
PGPObjectFactory factory = new PGPObjectFactory(keysBytes);
PGPKeyRing keyRing = null;
try {
if ((keyRing = (PGPKeyRing) factory.nextObject()) == null) {
Log.e(Constants.TAG, "No keys given!");
}
} catch (IOException e) {
Log.e(Constants.TAG, "Error while converting to PGPKeyRing!", e);
}
return keyRing;
}
/**
* Convert from byte[] to ArrayList<PGPSecretKey>
*
* @param keysBytes
* @return
*/
public static ArrayList<PGPSecretKey> BytesToPGPSecretKeyList(byte[] keysBytes) {
PGPSecretKeyRing keyRing = (PGPSecretKeyRing) BytesToPGPKeyRing(keysBytes);
ArrayList<PGPSecretKey> keys = new ArrayList<PGPSecretKey>();
@SuppressWarnings("unchecked")
Iterator<PGPSecretKey> itr = keyRing.getSecretKeys();
while (itr.hasNext()) {
keys.add(itr.next());
}
return keys;
}
/**
* Convert from byte[] to PGPSecretKey
*
* Singles keys are encoded as keyRings with one single key in it by Bouncy Castle
*
* @param keysBytes
* @return
*/
public static PGPSecretKey BytesToPGPSecretKey(byte[] keyBytes) {
PGPSecretKey key = BytesToPGPSecretKeyList(keyBytes).get(0);
return key;
}
/**
* Convert from ArrayList<PGPSecretKey> to byte[]
*
* @param keys
* @return
*/
public static byte[] PGPSecretKeyArrayListToBytes(ArrayList<PGPSecretKey> keys) {
ByteArrayOutputStream os = new ByteArrayOutputStream();
for (PGPSecretKey key : keys) {
try {
key.encode(os);
} catch (IOException e) {
Log.e(Constants.TAG, "Error while converting ArrayList<PGPSecretKey> to byte[]!", e);
}
}
return os.toByteArray();
}
/**
* Convert from PGPSecretKey to byte[]
*
* @param keysBytes
* @return
*/
public static byte[] PGPSecretKeyToBytes(PGPSecretKey key) {
try {
return key.getEncoded();
} catch (IOException e) {
Log.e(Constants.TAG, "Encoding failed", e);
return null;
}
}
/**
* Convert from PGPSecretKeyRing to byte[]
*
* @param keysBytes
* @return
*/
public static byte[] PGPSecretKeyRingToBytes(PGPSecretKeyRing keyRing) {
try {
return keyRing.getEncoded();
} catch (IOException e) {
Log.e(Constants.TAG, "Encoding failed", e);
return null;
}
}
}

View File

@@ -0,0 +1,510 @@
/*
* Copyright (C) 2012 Dominik Schürmann <dominik@dominikschuermann.de>
* Copyright (C) 2010 Thialfihar <thi@thialfihar.org>
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
* You may obtain a copy of the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and
* limitations under the License.
*/
package org.sufficientlysecure.keychain.pgp;
import java.util.Calendar;
import java.util.Date;
import java.util.GregorianCalendar;
import java.util.Locale;
import java.util.Vector;
import org.spongycastle.bcpg.sig.KeyFlags;
import org.spongycastle.openpgp.PGPPublicKey;
import org.spongycastle.openpgp.PGPPublicKeyRing;
import org.spongycastle.openpgp.PGPSecretKey;
import org.spongycastle.openpgp.PGPSecretKeyRing;
import org.spongycastle.openpgp.PGPSignature;
import org.spongycastle.openpgp.PGPSignatureSubpacketVector;
import org.sufficientlysecure.keychain.Constants;
import org.sufficientlysecure.keychain.R;
import org.sufficientlysecure.keychain.provider.ProviderHelper;
import org.sufficientlysecure.keychain.util.IterableIterator;
import org.sufficientlysecure.keychain.util.Log;
import android.content.Context;
public class PgpHelper {
public static Date getCreationDate(PGPPublicKey key) {
return key.getCreationTime();
}
public static Date getCreationDate(PGPSecretKey key) {
return key.getPublicKey().getCreationTime();
}
@SuppressWarnings("unchecked")
public static PGPPublicKey getMasterKey(PGPPublicKeyRing keyRing) {
if (keyRing == null) {
return null;
}
for (PGPPublicKey key : new IterableIterator<PGPPublicKey>(keyRing.getPublicKeys())) {
if (key.isMasterKey()) {
return key;
}
}
return null;
}
@SuppressWarnings("unchecked")
public static PGPSecretKey getMasterKey(PGPSecretKeyRing keyRing) {
if (keyRing == null) {
return null;
}
for (PGPSecretKey key : new IterableIterator<PGPSecretKey>(keyRing.getSecretKeys())) {
if (key.isMasterKey()) {
return key;
}
}
return null;
}
@SuppressWarnings("unchecked")
public static PGPSecretKey getKeyNum(PGPSecretKeyRing keyRing, long num) {
long cnt = 0;
if (keyRing == null) {
return null;
}
for (PGPSecretKey key : new IterableIterator<PGPSecretKey>(keyRing.getSecretKeys())) {
if (cnt == num) {
return key;
}
cnt++;
}
return null;
}
@SuppressWarnings("unchecked")
public static Vector<PGPPublicKey> getEncryptKeys(PGPPublicKeyRing keyRing) {
Vector<PGPPublicKey> encryptKeys = new Vector<PGPPublicKey>();
for (PGPPublicKey key : new IterableIterator<PGPPublicKey>(keyRing.getPublicKeys())) {
if (isEncryptionKey(key)) {
encryptKeys.add(key);
}
}
return encryptKeys;
}
@SuppressWarnings("unchecked")
public static Vector<PGPSecretKey> getSigningKeys(PGPSecretKeyRing keyRing) {
Vector<PGPSecretKey> signingKeys = new Vector<PGPSecretKey>();
for (PGPSecretKey key : new IterableIterator<PGPSecretKey>(keyRing.getSecretKeys())) {
if (isSigningKey(key)) {
signingKeys.add(key);
}
}
return signingKeys;
}
@SuppressWarnings("unchecked")
public static Vector<PGPSecretKey> getCertificationKeys(PGPSecretKeyRing keyRing) {
Vector<PGPSecretKey> signingKeys = new Vector<PGPSecretKey>();
for (PGPSecretKey key : new IterableIterator<PGPSecretKey>(keyRing.getSecretKeys())) {
if (isCertificationKey(key)) {
signingKeys.add(key);
}
}
return signingKeys;
}
public static Vector<PGPPublicKey> getUsableEncryptKeys(PGPPublicKeyRing keyRing) {
Vector<PGPPublicKey> usableKeys = new Vector<PGPPublicKey>();
Vector<PGPPublicKey> encryptKeys = getEncryptKeys(keyRing);
PGPPublicKey masterKey = null;
for (int i = 0; i < encryptKeys.size(); ++i) {
PGPPublicKey key = encryptKeys.get(i);
if (!isExpired(key)) {
if (key.isMasterKey()) {
masterKey = key;
} else {
usableKeys.add(key);
}
}
}
if (masterKey != null) {
usableKeys.add(masterKey);
}
return usableKeys;
}
public static boolean isExpired(PGPPublicKey key) {
Date creationDate = getCreationDate(key);
Date expiryDate = getExpiryDate(key);
Date now = new Date();
if (now.compareTo(creationDate) >= 0
&& (expiryDate == null || now.compareTo(expiryDate) <= 0)) {
return false;
}
return true;
}
public static boolean isExpired(PGPSecretKey key) {
return isExpired(key.getPublicKey());
}
public static Vector<PGPSecretKey> getUsableCertificationKeys(PGPSecretKeyRing keyRing) {
Vector<PGPSecretKey> usableKeys = new Vector<PGPSecretKey>();
Vector<PGPSecretKey> signingKeys = getCertificationKeys(keyRing);
PGPSecretKey masterKey = null;
for (int i = 0; i < signingKeys.size(); ++i) {
PGPSecretKey key = signingKeys.get(i);
if (key.isMasterKey()) {
masterKey = key;
} else {
usableKeys.add(key);
}
}
if (masterKey != null) {
usableKeys.add(masterKey);
}
return usableKeys;
}
public static Vector<PGPSecretKey> getUsableSigningKeys(PGPSecretKeyRing keyRing) {
Vector<PGPSecretKey> usableKeys = new Vector<PGPSecretKey>();
Vector<PGPSecretKey> signingKeys = getSigningKeys(keyRing);
PGPSecretKey masterKey = null;
for (int i = 0; i < signingKeys.size(); ++i) {
PGPSecretKey key = signingKeys.get(i);
if (key.isMasterKey()) {
masterKey = key;
} else {
usableKeys.add(key);
}
}
if (masterKey != null) {
usableKeys.add(masterKey);
}
return usableKeys;
}
public static Date getExpiryDate(PGPPublicKey key) {
Date creationDate = getCreationDate(key);
if (key.getValidDays() == 0) {
// no expiry
return null;
}
Calendar calendar = GregorianCalendar.getInstance();
calendar.setTime(creationDate);
calendar.add(Calendar.DATE, key.getValidDays());
Date expiryDate = calendar.getTime();
return expiryDate;
}
public static Date getExpiryDate(PGPSecretKey key) {
return getExpiryDate(key.getPublicKey());
}
public static PGPPublicKey getEncryptPublicKey(Context context, long masterKeyId) {
PGPPublicKeyRing keyRing = ProviderHelper.getPGPPublicKeyRingByMasterKeyId(context,
masterKeyId);
if (keyRing == null) {
Log.e(Constants.TAG, "keyRing is null!");
return null;
}
Vector<PGPPublicKey> encryptKeys = getUsableEncryptKeys(keyRing);
if (encryptKeys.size() == 0) {
Log.e(Constants.TAG, "encryptKeys is null!");
return null;
}
return encryptKeys.get(0);
}
public static PGPSecretKey getCertificationKey(Context context, long masterKeyId) {
PGPSecretKeyRing keyRing = ProviderHelper.getPGPSecretKeyRingByMasterKeyId(context,
masterKeyId);
if (keyRing == null) {
return null;
}
Vector<PGPSecretKey> signingKeys = getUsableCertificationKeys(keyRing);
if (signingKeys.size() == 0) {
return null;
}
return signingKeys.get(0);
}
public static PGPSecretKey getSigningKey(Context context, long masterKeyId) {
PGPSecretKeyRing keyRing = ProviderHelper.getPGPSecretKeyRingByMasterKeyId(context,
masterKeyId);
if (keyRing == null) {
return null;
}
Vector<PGPSecretKey> signingKeys = getUsableSigningKeys(keyRing);
if (signingKeys.size() == 0) {
return null;
}
return signingKeys.get(0);
}
@SuppressWarnings("unchecked")
public static String getMainUserId(PGPPublicKey key) {
for (String userId : new IterableIterator<String>(key.getUserIDs())) {
return userId;
}
return null;
}
@SuppressWarnings("unchecked")
public static String getMainUserId(PGPSecretKey key) {
for (String userId : new IterableIterator<String>(key.getUserIDs())) {
return userId;
}
return null;
}
public static String getMainUserIdSafe(Context context, PGPPublicKey key) {
String userId = getMainUserId(key);
if (userId == null || userId.equals("")) {
userId = context.getString(R.string.unknownUserId);
}
return userId;
}
public static String getMainUserIdSafe(Context context, PGPSecretKey key) {
String userId = getMainUserId(key);
if (userId == null || userId.equals("")) {
userId = context.getString(R.string.unknownUserId);
}
return userId;
}
@SuppressWarnings("unchecked")
public static boolean isEncryptionKey(PGPPublicKey key) {
if (!key.isEncryptionKey()) {
return false;
}
if (key.getVersion() <= 3) {
// this must be true now
return key.isEncryptionKey();
}
// special cases
if (key.getAlgorithm() == PGPPublicKey.ELGAMAL_ENCRYPT) {
return true;
}
if (key.getAlgorithm() == PGPPublicKey.RSA_ENCRYPT) {
return true;
}
for (PGPSignature sig : new IterableIterator<PGPSignature>(key.getSignatures())) {
if (key.isMasterKey() && sig.getKeyID() != key.getKeyID()) {
continue;
}
PGPSignatureSubpacketVector hashed = sig.getHashedSubPackets();
if (hashed != null
&& (hashed.getKeyFlags() & (KeyFlags.ENCRYPT_COMMS | KeyFlags.ENCRYPT_STORAGE)) != 0) {
return true;
}
PGPSignatureSubpacketVector unhashed = sig.getUnhashedSubPackets();
if (unhashed != null
&& (unhashed.getKeyFlags() & (KeyFlags.ENCRYPT_COMMS | KeyFlags.ENCRYPT_STORAGE)) != 0) {
return true;
}
}
return false;
}
public static boolean isEncryptionKey(PGPSecretKey key) {
return isEncryptionKey(key.getPublicKey());
}
@SuppressWarnings("unchecked")
public static boolean isSigningKey(PGPPublicKey key) {
if (key.getVersion() <= 3) {
return true;
}
// special case
if (key.getAlgorithm() == PGPPublicKey.RSA_SIGN) {
return true;
}
for (PGPSignature sig : new IterableIterator<PGPSignature>(key.getSignatures())) {
if (key.isMasterKey() && sig.getKeyID() != key.getKeyID()) {
continue;
}
PGPSignatureSubpacketVector hashed = sig.getHashedSubPackets();
if (hashed != null && (hashed.getKeyFlags() & KeyFlags.SIGN_DATA) != 0) {
return true;
}
PGPSignatureSubpacketVector unhashed = sig.getUnhashedSubPackets();
if (unhashed != null && (unhashed.getKeyFlags() & KeyFlags.SIGN_DATA) != 0) {
return true;
}
}
return false;
}
public static boolean isSigningKey(PGPSecretKey key) {
return isSigningKey(key.getPublicKey());
}
@SuppressWarnings("unchecked")
public static boolean isCertificationKey(PGPPublicKey key) {
if (key.getVersion() <= 3) {
return true;
}
for (PGPSignature sig : new IterableIterator<PGPSignature>(key.getSignatures())) {
if (key.isMasterKey() && sig.getKeyID() != key.getKeyID()) {
continue;
}
PGPSignatureSubpacketVector hashed = sig.getHashedSubPackets();
if (hashed != null && (hashed.getKeyFlags() & KeyFlags.CERTIFY_OTHER) != 0) {
return true;
}
PGPSignatureSubpacketVector unhashed = sig.getUnhashedSubPackets();
if (unhashed != null && (unhashed.getKeyFlags() & KeyFlags.CERTIFY_OTHER) != 0) {
return true;
}
}
return false;
}
public static boolean isCertificationKey(PGPSecretKey key) {
return isCertificationKey(key.getPublicKey());
}
public static String getAlgorithmInfo(PGPPublicKey key) {
return getAlgorithmInfo(key.getAlgorithm(), key.getBitStrength());
}
public static String getAlgorithmInfo(PGPSecretKey key) {
return getAlgorithmInfo(key.getPublicKey());
}
public static String getAlgorithmInfo(int algorithm, int keySize) {
String algorithmStr = null;
switch (algorithm) {
case PGPPublicKey.RSA_ENCRYPT:
case PGPPublicKey.RSA_GENERAL:
case PGPPublicKey.RSA_SIGN: {
algorithmStr = "RSA";
break;
}
case PGPPublicKey.DSA: {
algorithmStr = "DSA";
break;
}
case PGPPublicKey.ELGAMAL_ENCRYPT:
case PGPPublicKey.ELGAMAL_GENERAL: {
algorithmStr = "ElGamal";
break;
}
default: {
algorithmStr = "???";
break;
}
}
return algorithmStr + ", " + keySize + "bit";
}
public static String convertFingerprintToHex(byte[] fp) {
String fingerPrint = "";
for (int i = 0; i < fp.length; ++i) {
if (i != 0 && i % 10 == 0) {
fingerPrint += " ";
} else if (i != 0 && i % 2 == 0) {
fingerPrint += " ";
}
String chunk = Integer.toHexString((fp[i] + 256) % 256).toUpperCase(Locale.US);
while (chunk.length() < 2) {
chunk = "0" + chunk;
}
fingerPrint += chunk;
}
return fingerPrint;
}
public static String getFingerPrint(Context context, long keyId) {
PGPPublicKey key = ProviderHelper.getPGPPublicKeyByKeyId(context, keyId);
// if it is no public key get it from your own keys...
if (key == null) {
PGPSecretKey secretKey = ProviderHelper.getPGPSecretKeyByKeyId(context, keyId);
if (secretKey == null) {
Log.e(Constants.TAG, "Key could not be found!");
return null;
}
key = secretKey.getPublicKey();
}
return convertFingerprintToHex(key.getFingerprint());
}
public static boolean isSecretKeyPrivateEmpty(PGPSecretKey secretKey) {
return secretKey.isPrivateKeyEmpty();
}
public static boolean isSecretKeyPrivateEmpty(Context context, long keyId) {
PGPSecretKey secretKey = ProviderHelper.getPGPSecretKeyByKeyId(context, keyId);
if (secretKey == null) {
Log.e(Constants.TAG, "Key could not be found!");
return false; // could be a public key, assume it is not empty
}
return isSecretKeyPrivateEmpty(secretKey);
}
public static String getSmallFingerPrint(long keyId) {
String fingerPrint = Long.toHexString(keyId & 0xffffffffL).toUpperCase(Locale.US);
while (fingerPrint.length() < 8) {
fingerPrint = "0" + fingerPrint;
}
return fingerPrint;
}
public static String keyToHex(long keyId) {
return getSmallFingerPrint(keyId >> 32) + getSmallFingerPrint(keyId);
}
public static long keyFromHex(String data) {
int len = data.length();
String s2 = data.substring(len - 8);
String s1 = data.substring(0, len - 8);
return (Long.parseLong(s1, 16) << 32) | Long.parseLong(s2, 16);
}
}

File diff suppressed because it is too large Load Diff

View File

@@ -0,0 +1,307 @@
package org.sufficientlysecure.keychain.pgp;
import java.io.IOException;
import java.math.BigInteger;
import java.security.InvalidKeyException;
import java.security.NoSuchAlgorithmException;
import java.security.NoSuchProviderException;
import java.security.PrivateKey;
import java.security.PublicKey;
import java.security.SignatureException;
import java.security.cert.CertificateException;
import java.security.cert.X509Certificate;
import java.text.DateFormat;
import java.util.Date;
import java.util.Iterator;
import java.util.Vector;
import javax.security.auth.callback.Callback;
import javax.security.auth.callback.CallbackHandler;
import javax.security.auth.callback.PasswordCallback;
import javax.security.auth.callback.UnsupportedCallbackException;
import org.spongycastle.asn1.DERObjectIdentifier;
import org.spongycastle.asn1.x509.AuthorityKeyIdentifier;
import org.spongycastle.asn1.x509.BasicConstraints;
import org.spongycastle.asn1.x509.GeneralName;
import org.spongycastle.asn1.x509.GeneralNames;
import org.spongycastle.asn1.x509.SubjectKeyIdentifier;
import org.spongycastle.asn1.x509.X509Extensions;
import org.spongycastle.asn1.x509.X509Name;
import org.spongycastle.openpgp.PGPException;
import org.spongycastle.openpgp.PGPPrivateKey;
import org.spongycastle.openpgp.PGPPublicKey;
import org.spongycastle.openpgp.PGPSecretKey;
import org.spongycastle.x509.X509V3CertificateGenerator;
import org.spongycastle.x509.extension.AuthorityKeyIdentifierStructure;
import org.spongycastle.x509.extension.SubjectKeyIdentifierStructure;
import org.sufficientlysecure.keychain.Constants;
import org.sufficientlysecure.keychain.util.Log;
public class PgpToX509 {
public final static String DN_COMMON_PART_O = "OpenPGP to X.509 Bridge";
public final static String DN_COMMON_PART_OU = "OpenPGP Keychain cert";
/**
* Creates a self-signed certificate from a public and private key. The (critical) key-usage
* extension is set up with: digital signature, non-repudiation, key-encipherment, key-agreement
* and certificate-signing. The (non-critical) Netscape extension is set up with: SSL client and
* S/MIME. A URI subjectAltName may also be set up.
*
* @param pubKey
* public key
* @param privKey
* private key
* @param subject
* subject (and issuer) DN for this certificate, RFC 2253 format preferred.
* @param startDate
* date from which the certificate will be valid (defaults to current date and time
* if null)
* @param endDate
* date until which the certificate will be valid (defaults to current date and time
* if null) *
* @param subjAltNameURI
* URI to be placed in subjectAltName
* @return self-signed certificate
* @throws InvalidKeyException
* @throws SignatureException
* @throws NoSuchAlgorithmException
* @throws IllegalStateException
* @throws NoSuchProviderException
* @throws CertificateException
* @throws Exception
*
* @author Bruno Harbulot
*/
public static X509Certificate createSelfSignedCert(PublicKey pubKey, PrivateKey privKey,
X509Name subject, Date startDate, Date endDate, String subjAltNameURI)
throws InvalidKeyException, IllegalStateException, NoSuchAlgorithmException,
SignatureException, CertificateException, NoSuchProviderException {
X509V3CertificateGenerator certGenerator = new X509V3CertificateGenerator();
certGenerator.reset();
/*
* Sets up the subject distinguished name. Since it's a self-signed certificate, issuer and
* subject are the same.
*/
certGenerator.setIssuerDN(subject);
certGenerator.setSubjectDN(subject);
/*
* Sets up the validity dates.
*/
if (startDate == null) {
startDate = new Date(System.currentTimeMillis());
}
certGenerator.setNotBefore(startDate);
if (endDate == null) {
endDate = new Date(startDate.getTime() + (365L * 24L * 60L * 60L * 1000L));
Log.d(Constants.TAG, "end date is=" + DateFormat.getDateInstance().format(endDate));
}
certGenerator.setNotAfter(endDate);
/*
* The serial-number of this certificate is 1. It makes sense because it's self-signed.
*/
certGenerator.setSerialNumber(BigInteger.ONE);
/*
* Sets the public-key to embed in this certificate.
*/
certGenerator.setPublicKey(pubKey);
/*
* Sets the signature algorithm.
*/
String pubKeyAlgorithm = pubKey.getAlgorithm();
if (pubKeyAlgorithm.equals("DSA")) {
certGenerator.setSignatureAlgorithm("SHA1WithDSA");
} else if (pubKeyAlgorithm.equals("RSA")) {
certGenerator.setSignatureAlgorithm("SHA1WithRSAEncryption");
} else {
RuntimeException re = new RuntimeException("Algorithm not recognised: "
+ pubKeyAlgorithm);
Log.e(Constants.TAG, re.getMessage(), re);
throw re;
}
/*
* Adds the Basic Constraint (CA: true) extension.
*/
certGenerator.addExtension(X509Extensions.BasicConstraints, true,
new BasicConstraints(true));
/*
* Adds the subject key identifier extension.
*/
SubjectKeyIdentifier subjectKeyIdentifier = new SubjectKeyIdentifierStructure(pubKey);
certGenerator
.addExtension(X509Extensions.SubjectKeyIdentifier, false, subjectKeyIdentifier);
/*
* Adds the authority key identifier extension.
*/
AuthorityKeyIdentifier authorityKeyIdentifier = new AuthorityKeyIdentifierStructure(pubKey);
certGenerator.addExtension(X509Extensions.AuthorityKeyIdentifier, false,
authorityKeyIdentifier);
/*
* Adds the subject alternative-name extension.
*/
if (subjAltNameURI != null) {
GeneralNames subjectAltNames = new GeneralNames(new GeneralName(
GeneralName.uniformResourceIdentifier, subjAltNameURI));
certGenerator.addExtension(X509Extensions.SubjectAlternativeName, false,
subjectAltNames);
}
/*
* Creates and sign this certificate with the private key corresponding to the public key of
* the certificate (hence the name "self-signed certificate").
*/
X509Certificate cert = certGenerator.generate(privKey);
/*
* Checks that this certificate has indeed been correctly signed.
*/
cert.verify(pubKey);
return cert;
}
/**
* Creates a self-signed certificate from a PGP Secret Key.
*
* @param pgpSecKey
* PGP Secret Key (from which one can extract the public and private keys and other
* attributes).
* @param pgpPrivKey
* PGP Private Key corresponding to the Secret Key (password callbacks should be done
* before calling this method)
* @param subjAltNameURI
* optional URI to embed in the subject alternative-name
* @return self-signed certificate
* @throws PGPException
* @throws NoSuchProviderException
* @throws InvalidKeyException
* @throws NoSuchAlgorithmException
* @throws SignatureException
* @throws CertificateException
*
* @author Bruno Harbulot
*/
public static X509Certificate createSelfSignedCert(PGPSecretKey pgpSecKey,
PGPPrivateKey pgpPrivKey, String subjAltNameURI) throws PGPException,
NoSuchProviderException, InvalidKeyException, NoSuchAlgorithmException,
SignatureException, CertificateException {
// get public key from secret key
PGPPublicKey pgpPubKey = pgpSecKey.getPublicKey();
// LOGGER.info("Key ID: " + Long.toHexString(pgpPubKey.getKeyID() & 0xffffffffL));
/*
* The X.509 Name to be the subject DN is prepared. The CN is extracted from the Secret Key
* user ID.
*/
Vector<DERObjectIdentifier> x509NameOids = new Vector<DERObjectIdentifier>();
Vector<String> x509NameValues = new Vector<String>();
x509NameOids.add(X509Name.O);
x509NameValues.add(DN_COMMON_PART_O);
x509NameOids.add(X509Name.OU);
x509NameValues.add(DN_COMMON_PART_OU);
for (@SuppressWarnings("unchecked")
Iterator<Object> it = (Iterator<Object>) pgpSecKey.getUserIDs(); it.hasNext();) {
Object attrib = it.next();
x509NameOids.add(X509Name.CN);
x509NameValues.add("CryptoCall");
// x509NameValues.add(attrib.toString());
}
/*
* Currently unused.
*/
Log.d(Constants.TAG, "User attributes: ");
for (@SuppressWarnings("unchecked")
Iterator<Object> it = (Iterator<Object>) pgpSecKey.getUserAttributes(); it.hasNext();) {
Object attrib = it.next();
Log.d(Constants.TAG, " - " + attrib + " -- " + attrib.getClass());
}
X509Name x509name = new X509Name(x509NameOids, x509NameValues);
Log.d(Constants.TAG, "Subject DN: " + x509name);
/*
* To check the signature from the certificate on the recipient side, the creation time
* needs to be embedded in the certificate. It seems natural to make this creation time be
* the "not-before" date of the X.509 certificate. Unlimited PGP keys have a validity of 0
* second. In this case, the "not-after" date will be the same as the not-before date. This
* is something that needs to be checked by the service receiving this certificate.
*/
Date creationTime = pgpPubKey.getCreationTime();
Log.d(Constants.TAG,
"pgp pub key creation time=" + DateFormat.getDateInstance().format(creationTime));
Log.d(Constants.TAG, "pgp valid seconds=" + pgpPubKey.getValidSeconds());
Date validTo = null;
if (pgpPubKey.getValidSeconds() > 0) {
validTo = new Date(creationTime.getTime() + 1000L * pgpPubKey.getValidSeconds());
}
X509Certificate selfSignedCert = createSelfSignedCert(
pgpPubKey.getKey(PgpMain.BOUNCY_CASTLE_PROVIDER_NAME), pgpPrivKey.getKey(),
x509name, creationTime, validTo, subjAltNameURI);
return selfSignedCert;
}
/**
* This is a password callback handler that will fill in a password automatically. Useful to
* configure passwords in advance, but should be used with caution depending on how much you
* allow passwords to be stored within your application.
*
* @author Bruno Harbulot.
*
*/
public final static class PredefinedPasswordCallbackHandler implements CallbackHandler {
private char[] password;
private String prompt;
public PredefinedPasswordCallbackHandler(String password) {
this(password == null ? null : password.toCharArray(), null);
}
public PredefinedPasswordCallbackHandler(char[] password) {
this(password, null);
}
public PredefinedPasswordCallbackHandler(String password, String prompt) {
this(password == null ? null : password.toCharArray(), prompt);
}
public PredefinedPasswordCallbackHandler(char[] password, String prompt) {
this.password = password;
this.prompt = prompt;
}
public void handle(Callback[] callbacks) throws IOException, UnsupportedCallbackException {
for (Callback callback : callbacks) {
if (callback instanceof PasswordCallback) {
PasswordCallback pwCallback = (PasswordCallback) callback;
if ((this.prompt == null) || (this.prompt.equals(pwCallback.getPrompt()))) {
pwCallback.setPassword(this.password);
}
} else {
throw new UnsupportedCallbackException(callback, "Unrecognised callback.");
}
}
}
protected final Object clone() throws CloneNotSupportedException {
throw new CloneNotSupportedException();
}
}
}