3
0
mirror of https://github.com/Qortal/altcoinj.git synced 2025-02-14 11:15:51 +00:00

Payment protocol: misc enhancements.

Stop using the JDK store and use our own, to make the StartSSL fix effective.
Include the certs in the exception thrown if the chain doesn't verify.
Support loading from a file in the PaymentProtocol tool.
Print the certs out in the PaymentProtocol tool if there's an error.
This commit is contained in:
Mike Hearn 2014-03-23 19:21:42 +01:00
parent feecc8f486
commit 0ed260bae2
3 changed files with 45 additions and 10 deletions

View File

@ -16,6 +16,9 @@
package com.google.bitcoin.protocols.payments; package com.google.bitcoin.protocols.payments;
import java.security.cert.X509Certificate;
import java.util.List;
public class PaymentRequestException extends Exception { public class PaymentRequestException extends Exception {
public PaymentRequestException(String msg) { public PaymentRequestException(String msg) {
super(msg); super(msg);
@ -86,6 +89,8 @@ public class PaymentRequestException extends Exception {
} }
public static class PkiVerificationException extends PaymentRequestException { public static class PkiVerificationException extends PaymentRequestException {
public List<X509Certificate> certificates;
public PkiVerificationException(String msg) { public PkiVerificationException(String msg) {
super(msg); super(msg);
} }
@ -93,5 +98,10 @@ public class PaymentRequestException extends Exception {
public PkiVerificationException(Exception e) { public PkiVerificationException(Exception e) {
super(e); super(e);
} }
public PkiVerificationException(Exception e, List<X509Certificate> certificates) {
super(e);
this.certificates = certificates;
}
} }
} }

View File

@ -441,6 +441,7 @@ public class PaymentSession {
* Returns null if no PKI method was specified in the {@link Protos.PaymentRequest}. * Returns null if no PKI method was specified in the {@link Protos.PaymentRequest}.
*/ */
public @Nullable PkiVerificationData verifyPki() throws PaymentRequestException { public @Nullable PkiVerificationData verifyPki() throws PaymentRequestException {
List<X509Certificate> certs = null;
try { try {
if (pkiVerificationData != null) if (pkiVerificationData != null)
return pkiVerificationData; return pkiVerificationData;
@ -464,7 +465,7 @@ public class PaymentSession {
// The ordering of certificates is defined by the payment protocol spec to be the same as what the Java // The ordering of certificates is defined by the payment protocol spec to be the same as what the Java
// crypto API requires - convenient! // crypto API requires - convenient!
CertificateFactory certificateFactory = CertificateFactory.getInstance("X.509"); CertificateFactory certificateFactory = CertificateFactory.getInstance("X.509");
List<X509Certificate> certs = Lists.newArrayList(); certs = Lists.newArrayList();
for (ByteString bytes : protoCerts.getCertificateList()) for (ByteString bytes : protoCerts.getCertificateList())
certs.add((X509Certificate) certificateFactory.generateCertificate(bytes.newInput())); certs.add((X509Certificate) certificateFactory.generateCertificate(bytes.newInput()));
CertPath path = certificateFactory.generateCertPath(certs); CertPath path = certificateFactory.generateCertPath(certs);
@ -536,7 +537,7 @@ public class PaymentSession {
} catch (CertPathValidatorException e) { } catch (CertPathValidatorException e) {
// The certificate chain isn't known or trusted, probably, the server is using an SSL root we don't // The certificate chain isn't known or trusted, probably, the server is using an SSL root we don't
// know about and the user needs to upgrade to a new version of the software (or import a root cert). // know about and the user needs to upgrade to a new version of the software (or import a root cert).
throw new PaymentRequestException.PkiVerificationException(e); throw new PaymentRequestException.PkiVerificationException(e, certs);
} catch (InvalidKeyException e) { } catch (InvalidKeyException e) {
// Shouldn't happen if the certs verified correctly. // Shouldn't happen if the certs verified correctly.
throw new PaymentRequestException.PkiVerificationException(e); throw new PaymentRequestException.PkiVerificationException(e);
@ -586,8 +587,7 @@ public class PaymentSession {
path = System.getProperty("javax.net.ssl.trustStore"); path = System.getProperty("javax.net.ssl.trustStore");
} }
if (path == null) { if (path == null) {
// Try this default system location for Linux/Windows/OSX. return loadFallbackStore(defaultPassword);
path = System.getProperty("java.home") + "/lib/security/cacerts".replace('/', File.separatorChar);
} }
try { try {
KeyStore keyStore = KeyStore.getInstance(keyStoreType); KeyStore keyStore = KeyStore.getInstance(keyStoreType);
@ -597,13 +597,17 @@ public class PaymentSession {
} catch (FileNotFoundException e) { } catch (FileNotFoundException e) {
// If we failed to find a system trust store, load our own fallback trust store. This can fail on Android // If we failed to find a system trust store, load our own fallback trust store. This can fail on Android
// but we should never reach it there. // but we should never reach it there.
KeyStore keyStore = KeyStore.getInstance("JKS"); return loadFallbackStore(defaultPassword);
InputStream is = getClass().getResourceAsStream("cacerts");
keyStore.load(is, defaultPassword);
return keyStore;
} }
} }
private KeyStore loadFallbackStore(char[] defaultPassword) throws KeyStoreException, IOException, NoSuchAlgorithmException, CertificateException {
KeyStore keyStore = KeyStore.getInstance("JKS");
InputStream is = getClass().getResourceAsStream("cacerts");
keyStore.load(is, defaultPassword);
return keyStore;
}
private void parsePaymentRequest(Protos.PaymentRequest request) throws PaymentRequestException { private void parsePaymentRequest(Protos.PaymentRequest request) throws PaymentRequestException {
try { try {
if (request == null) if (request == null)

View File

@ -20,9 +20,14 @@ import com.google.bitcoin.protocols.payments.PaymentRequestException;
import com.google.bitcoin.protocols.payments.PaymentSession; import com.google.bitcoin.protocols.payments.PaymentSession;
import com.google.bitcoin.uri.BitcoinURI; import com.google.bitcoin.uri.BitcoinURI;
import com.google.bitcoin.uri.BitcoinURIParseException; import com.google.bitcoin.uri.BitcoinURIParseException;
import org.bitcoin.protocols.payments.Protos;
import java.io.FileInputStream;
import java.io.FileNotFoundException;
import java.io.IOException;
import java.net.URI; import java.net.URI;
import java.net.URISyntaxException; import java.net.URISyntaxException;
import java.security.cert.X509Certificate;
import java.util.Date; import java.util.Date;
import java.util.concurrent.ExecutionException; import java.util.concurrent.ExecutionException;
@ -42,7 +47,12 @@ public class PaymentProtocol {
try { try {
URI uri = new URI(arg); URI uri = new URI(arg);
PaymentSession session; PaymentSession session;
if (uri.getScheme().equals("http")) { if (arg.startsWith("/")) {
FileInputStream stream = new FileInputStream(arg);
Protos.PaymentRequest request = Protos.PaymentRequest.parseFrom(stream);
stream.close();
session = new PaymentSession(request);
} else if (uri.getScheme().equals("http")) {
session = PaymentSession.createFromUrl(arg).get(); session = PaymentSession.createFromUrl(arg).get();
} else if (uri.getScheme().equals("bitcoin")) { } else if (uri.getScheme().equals("bitcoin")) {
BitcoinURI bcuri = new BitcoinURI(arg); BitcoinURI bcuri = new BitcoinURI(arg);
@ -75,13 +85,24 @@ public class PaymentProtocol {
System.err.println("Could not parse URI: " + e.getMessage()); System.err.println("Could not parse URI: " + e.getMessage());
} catch (BitcoinURIParseException e) { } catch (BitcoinURIParseException e) {
System.err.println("Could not parse URI: " + e.getMessage()); System.err.println("Could not parse URI: " + e.getMessage());
} catch (PaymentRequestException.PkiVerificationException e) {
System.err.println(e.getMessage());
if (e.certificates != null) {
for (X509Certificate certificate : e.certificates) {
System.err.println(" " + certificate);
}
}
} catch (PaymentRequestException e) { } catch (PaymentRequestException e) {
System.err.println("Could not handle payment URL: " + e.getMessage()); System.err.println("Could not handle payment request: " + e.getMessage());
} catch (InterruptedException e) { } catch (InterruptedException e) {
System.err.println("Interrupted whilst processing/downloading."); System.err.println("Interrupted whilst processing/downloading.");
} catch (ExecutionException e) { } catch (ExecutionException e) {
System.err.println("Failed whilst retrieving payment URL: " + e.getMessage()); System.err.println("Failed whilst retrieving payment URL: " + e.getMessage());
e.printStackTrace(); e.printStackTrace();
} catch (FileNotFoundException e) {
System.err.println(e.getMessage());
} catch (IOException e) {
e.printStackTrace();
} }
} }
} }