diff options
-rw-r--r-- | ojluni/src/main/java/sun/security/pkcs/ContentInfo.java | 8 | ||||
-rw-r--r-- | ojluni/src/main/java/sun/security/pkcs/PKCS7.java | 237 | ||||
-rw-r--r-- | ojluni/src/main/java/sun/security/pkcs/PKCS8Key.java | 19 |
3 files changed, 231 insertions, 33 deletions
diff --git a/ojluni/src/main/java/sun/security/pkcs/ContentInfo.java b/ojluni/src/main/java/sun/security/pkcs/ContentInfo.java index 2eb1b03f36..bc78d0f1c0 100644 --- a/ojluni/src/main/java/sun/security/pkcs/ContentInfo.java +++ b/ojluni/src/main/java/sun/security/pkcs/ContentInfo.java @@ -1,5 +1,5 @@ /* - * Copyright (c) 1996, 2005, Oracle and/or its affiliates. All rights reserved. + * Copyright (c) 1996, 2011, Oracle and/or its affiliates. All rights reserved. * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. * * This code is free software; you can redistribute it and/or modify it @@ -163,9 +163,9 @@ public class ContentInfo { } public byte[] getData() throws IOException { - if (contentType.equals(DATA_OID) || - contentType.equals(OLD_DATA_OID) || - contentType.equals(TIMESTAMP_TOKEN_INFO_OID)) { + if (contentType.equals((Object)DATA_OID) || + contentType.equals((Object)OLD_DATA_OID) || + contentType.equals((Object)TIMESTAMP_TOKEN_INFO_OID)) { if (content == null) return null; else diff --git a/ojluni/src/main/java/sun/security/pkcs/PKCS7.java b/ojluni/src/main/java/sun/security/pkcs/PKCS7.java index 5fb23ea945..c9973aa24f 100644 --- a/ojluni/src/main/java/sun/security/pkcs/PKCS7.java +++ b/ojluni/src/main/java/sun/security/pkcs/PKCS7.java @@ -1,6 +1,6 @@ /* * Copyright (C) 2014 The Android Open Source Project - * Copyright (c) 1996, 2011, Oracle and/or its affiliates. All rights reserved. + * Copyright (c) 1996, 2013, Oracle and/or its affiliates. All rights reserved. * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. * * This code is free software; you can redistribute it and/or modify it @@ -28,6 +28,7 @@ package sun.security.pkcs; import java.io.*; import java.math.BigInteger; +import java.net.URI; import java.util.*; import java.security.cert.X509Certificate; import java.security.cert.CertificateException; @@ -40,11 +41,12 @@ import java.security.cert.CRLException; import java.security.cert.CertificateFactory; import java.security.*; +import sun.security.timestamp.*; + import javax.security.auth.x500.X500Principal; import sun.security.util.*; import sun.security.x509.AlgorithmId; -import sun.security.x509.CertificateIssuerName; import sun.security.x509.X509CertImpl; import sun.security.x509.X509CertInfo; import sun.security.x509.X509CRLImpl; @@ -75,6 +77,36 @@ public class PKCS7 { private Principal[] certIssuerNames; + /* BEGIN ANDROID-REMOVED: unused in Android + /* + * Random number generator for creating nonce values + * (Lazy initialization) + * + private static class SecureRandomHolder { + static final SecureRandom RANDOM; + static { + SecureRandom tmp = null; + try { + tmp = SecureRandom.getInstance("SHA1PRNG"); + } catch (NoSuchAlgorithmException e) { + // should not happen + } + RANDOM = tmp; + } + } + + /* + * Object identifier for the timestamping key purpose. + * + private static final String KP_TIMESTAMPING_OID = "1.3.6.1.5.5.7.3.8"; + + /* + * Object identifier for extendedKeyUsage extension + * + private static final String EXTENDED_KEY_USAGE_OID = "2.5.29.37"; + + END ANDROID-REMOVED */ + /** * Unmarshals a PKCS7 block from its encoded form, parsing the * encoded bytes from the InputStream. @@ -161,12 +193,13 @@ public class PKCS7 { contentType = contentInfo.contentType; DerValue content = contentInfo.getContent(); - if (contentType.equals(ContentInfo.SIGNED_DATA_OID)) { + if (contentType.equals((Object)ContentInfo.SIGNED_DATA_OID)) { parseSignedData(content); - } else if (contentType.equals(ContentInfo.OLD_SIGNED_DATA_OID)) { + } else if (contentType.equals((Object)ContentInfo.OLD_SIGNED_DATA_OID)) { // This is for backwards compatibility with JDK 1.1.x parseOldSignedData(content); - } else if (contentType.equals(ContentInfo.NETSCAPE_CERT_SEQUENCE_OID)){ + } else if (contentType.equals((Object) + ContentInfo.NETSCAPE_CERT_SEQUENCE_OID)){ parseNetscapeCertChain(content); } else { throw new ParsingException("content type " + contentType + @@ -498,9 +531,7 @@ public class PKCS7 { byte[] encoded = certificates[i].getEncoded(); implCerts[i] = new X509CertImpl(encoded); } catch (CertificateException ce) { - IOException ie = new IOException(ce.getMessage()); - ie.initCause(ce); - throw ie; + throw new IOException(ce); } } } @@ -522,9 +553,7 @@ public class PKCS7 { byte[] encoded = crl.getEncoded(); implCRLs.add(new X509CRLImpl(encoded)); } catch (CRLException ce) { - IOException ie = new IOException(ce.getMessage()); - ie.initCause(ce); - throw ie; + throw new IOException(ce); } } } @@ -597,7 +626,7 @@ public class PKCS7 { intResult.addElement(signerInfo); } } - if (intResult.size() != 0) { + if (!intResult.isEmpty()) { SignerInfo[] result = new SignerInfo[intResult.size()]; intResult.copyInto(result); @@ -721,8 +750,8 @@ public class PKCS7 { X509CertInfo tbsCert = new X509CertInfo(cert.getTBSCertificate()); certIssuerName = (Principal) - tbsCert.get(CertificateIssuerName.NAME + "." + - CertificateIssuerName.DN_NAME); + tbsCert.get(X509CertInfo.ISSUER + "." + + X509CertInfo.DN_NAME); } catch (Exception e) { // error generating X500Name object from the cert's // issuer DN, leave name as is. @@ -772,6 +801,7 @@ public class PKCS7 { return this.oldStyle; } + // BEGIN ANDROID-ADDED /** * For legacy reasons we need to return exactly the original encoded certificate bytes, instead * of letting the underlying implementation have a shot at re-encoding the data. @@ -963,4 +993,183 @@ public class PKCS7 { wrapped.verify(key, sigProvider); } } + // END ANDROID-ADDED + + // BEGIN ANDROID-REMOVED: unused in Android + /** + * Assembles a PKCS #7 signed data message that optionally includes a + * signature timestamp. + * + * @param signature the signature bytes + * @param signerChain the signer's X.509 certificate chain + * @param content the content that is signed; specify null to not include + * it in the PKCS7 data + * @param signatureAlgorithm the name of the signature algorithm + * @param tsaURI the URI of the Timestamping Authority; or null if no + * timestamp is requested + * @param tSAPolicyID the TSAPolicyID of the Timestamping Authority as a + * numerical object identifier; or null if we leave the TSA server + * to choose one. This argument is only used when tsaURI is provided + * @return the bytes of the encoded PKCS #7 signed data message + * @throws NoSuchAlgorithmException The exception is thrown if the signature + * algorithm is unrecognised. + * @throws CertificateException The exception is thrown if an error occurs + * while processing the signer's certificate or the TSA's + * certificate. + * @throws IOException The exception is thrown if an error occurs while + * generating the signature timestamp or while generating the signed + * data message. + * + public static byte[] generateSignedData(byte[] signature, + X509Certificate[] signerChain, + byte[] content, + String signatureAlgorithm, + URI tsaURI, + String tSAPolicyID) + throws CertificateException, IOException, NoSuchAlgorithmException + { + + // Generate the timestamp token + PKCS9Attributes unauthAttrs = null; + if (tsaURI != null) { + // Timestamp the signature + HttpTimestamper tsa = new HttpTimestamper(tsaURI); + byte[] tsToken = generateTimestampToken(tsa, tSAPolicyID, signature); + + // Insert the timestamp token into the PKCS #7 signer info element + // (as an unsigned attribute) + unauthAttrs = + new PKCS9Attributes(new PKCS9Attribute[]{ + new PKCS9Attribute( + PKCS9Attribute.SIGNATURE_TIMESTAMP_TOKEN_STR, + tsToken)}); + } + + // Create the SignerInfo + X500Name issuerName = + X500Name.asX500Name(signerChain[0].getIssuerX500Principal()); + BigInteger serialNumber = signerChain[0].getSerialNumber(); + String encAlg = AlgorithmId.getEncAlgFromSigAlg(signatureAlgorithm); + String digAlg = AlgorithmId.getDigAlgFromSigAlg(signatureAlgorithm); + SignerInfo signerInfo = new SignerInfo(issuerName, serialNumber, + AlgorithmId.get(digAlg), null, + AlgorithmId.get(encAlg), + signature, unauthAttrs); + + // Create the PKCS #7 signed data message + SignerInfo[] signerInfos = {signerInfo}; + AlgorithmId[] algorithms = {signerInfo.getDigestAlgorithmId()}; + // Include or exclude content + ContentInfo contentInfo = (content == null) + ? new ContentInfo(ContentInfo.DATA_OID, null) + : new ContentInfo(content); + PKCS7 pkcs7 = new PKCS7(algorithms, contentInfo, + signerChain, signerInfos); + ByteArrayOutputStream p7out = new ByteArrayOutputStream(); + pkcs7.encodeSignedData(p7out); + + return p7out.toByteArray(); + } + + /** + * Requests, processes and validates a timestamp token from a TSA using + * common defaults. Uses the following defaults in the timestamp request: + * SHA-1 for the hash algorithm, a 64-bit nonce, and request certificate + * set to true. + * + * @param tsa the timestamping authority to use + * @param tSAPolicyID the TSAPolicyID of the Timestamping Authority as a + * numerical object identifier; or null if we leave the TSA server + * to choose one + * @param toBeTimestamped the token that is to be timestamped + * @return the encoded timestamp token + * @throws IOException The exception is thrown if an error occurs while + * communicating with the TSA, or a non-null + * TSAPolicyID is specified in the request but it + * does not match the one in the reply + * @throws CertificateException The exception is thrown if the TSA's + * certificate is not permitted for timestamping. + * + private static byte[] generateTimestampToken(Timestamper tsa, + String tSAPolicyID, + byte[] toBeTimestamped) + throws IOException, CertificateException + { + // Generate a timestamp + MessageDigest messageDigest = null; + TSRequest tsQuery = null; + try { + // SHA-1 is always used. + messageDigest = MessageDigest.getInstance("SHA-1"); + tsQuery = new TSRequest(tSAPolicyID, toBeTimestamped, messageDigest); + } catch (NoSuchAlgorithmException e) { + // ignore + } + + // Generate a nonce + BigInteger nonce = null; + if (SecureRandomHolder.RANDOM != null) { + nonce = new BigInteger(64, SecureRandomHolder.RANDOM); + tsQuery.setNonce(nonce); + } + tsQuery.requestCertificate(true); + + TSResponse tsReply = tsa.generateTimestamp(tsQuery); + int status = tsReply.getStatusCode(); + // Handle TSP error + if (status != 0 && status != 1) { + throw new IOException("Error generating timestamp: " + + tsReply.getStatusCodeAsText() + " " + + tsReply.getFailureCodeAsText()); + } + + if (tSAPolicyID != null && + !tSAPolicyID.equals(tsReply.getTimestampToken().getPolicyID())) { + throw new IOException("TSAPolicyID changed in " + + "timestamp token"); + } + PKCS7 tsToken = tsReply.getToken(); + + TimestampToken tst = tsReply.getTimestampToken(); + if (!tst.getHashAlgorithm().getName().equals("SHA-1")) { + throw new IOException("Digest algorithm not SHA-1 in " + + "timestamp token"); + } + if (!MessageDigest.isEqual(tst.getHashedMessage(), + tsQuery.getHashedMessage())) { + throw new IOException("Digest octets changed in timestamp token"); + } + + BigInteger replyNonce = tst.getNonce(); + if (replyNonce == null && nonce != null) { + throw new IOException("Nonce missing in timestamp token"); + } + if (replyNonce != null && !replyNonce.equals(nonce)) { + throw new IOException("Nonce changed in timestamp token"); + } + + // Examine the TSA's certificate (if present) + for (SignerInfo si: tsToken.getSignerInfos()) { + X509Certificate cert = si.getCertificate(tsToken); + if (cert == null) { + // Error, we've already set tsRequestCertificate = true + throw new CertificateException( + "Certificate not included in timestamp token"); + } else { + if (!cert.getCriticalExtensionOIDs().contains( + EXTENDED_KEY_USAGE_OID)) { + throw new CertificateException( + "Certificate is not valid for timestamping"); + } + List<String> keyPurposes = cert.getExtendedKeyUsage(); + if (keyPurposes == null || + !keyPurposes.contains(KP_TIMESTAMPING_OID)) { + throw new CertificateException( + "Certificate is not valid for timestamping"); + } + } + } + return tsReply.getEncodedToken(); + } + END ANDROID-REMOVED */ } diff --git a/ojluni/src/main/java/sun/security/pkcs/PKCS8Key.java b/ojluni/src/main/java/sun/security/pkcs/PKCS8Key.java index 6405c9fc93..59512f11b6 100644 --- a/ojluni/src/main/java/sun/security/pkcs/PKCS8Key.java +++ b/ojluni/src/main/java/sun/security/pkcs/PKCS8Key.java @@ -1,5 +1,5 @@ /* - * Copyright (c) 1996, 2004, Oracle and/or its affiliates. All rights reserved. + * Copyright (c) 1996, 2013, Oracle and/or its affiliates. All rights reserved. * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. * * This code is free software; you can redistribute it and/or modify it @@ -208,7 +208,7 @@ public class PKCS8Key implements PrivateKey { throw new InstantiationException(); } - Class keyClass = null; + Class<?> keyClass = null; try { keyClass = Class.forName(classname); } catch (ClassNotFoundException e) { @@ -304,17 +304,6 @@ public class PKCS8Key implements PrivateKey { return encodedKey.clone(); } - /* - * Returns a printable representation of the key - */ - public String toString () - { - HexDumpEncoder encoder = new HexDumpEncoder (); - - return "algorithm = " + algid.toString () - + ", unparsed keybits = \n" + encoder.encodeBuffer (key); - } - /** * Initialize an PKCS8Key object from an input stream. The data * on that input stream must be encoded using DER, obeying the @@ -342,9 +331,9 @@ public class PKCS8Key implements PrivateKey { BigInteger version = val.data.getBigInteger(); - if (!version.equals(this.version)) { + if (!version.equals(PKCS8Key.version)) { throw new IOException("version mismatch: (supported: " + - Debug.toHexString(this.version) + + Debug.toHexString(PKCS8Key.version) + ", parsed: " + Debug.toHexString(version)); } |