private String hostNameMessage(X509Certificate cert, String hostname) { StringBuffer si = new StringBuffer(); si.append(master.getString(R.string.mtm_hostname_mismatch, hostname)); si.append("\n\n"); try { Collection<List<?>> sans = cert.getSubjectAlternativeNames(); if (sans == null) { si.append(cert.getSubjectDN()); si.append("\n"); } else for (List<?> altName : sans) { Object name = altName.get(1); if (name instanceof String) { si.append("["); si.append((Integer) altName.get(0)); si.append("] "); si.append(name); si.append("\n"); } } } catch (CertificateParsingException e) { e.printStackTrace(); si.append("<Parsing error: "); si.append(e.getLocalizedMessage()); si.append(">\n"); } si.append("\n"); si.append(master.getString(R.string.mtm_connect_anyway)); si.append("\n\n"); si.append(master.getString(R.string.mtm_cert_details)); certDetails(si, cert); return si.toString(); }
/** * Extracts the array of SubjectAlt DNS names from an X509Certificate. Returns null if there * aren't any. * * <p>Note: Java doesn't appear able to extract international characters from the SubjectAlts. It * can only extract international characters from the CN field. * * <p>(Or maybe the version of OpenSSL I'm using to test isn't storing the international * characters correctly in the SubjectAlts?). * * @param cert X509Certificate * @return Array of SubjectALT DNS names stored in the certificate. */ public static String[] getDNSSubjectAlts(X509Certificate cert) { LinkedList subjectAltList = new LinkedList(); Collection c = null; try { c = cert.getSubjectAlternativeNames(); } catch (CertificateParsingException cpe) { // Should probably log.debug() this? cpe.printStackTrace(); } if (c != null) { Iterator it = c.iterator(); while (it.hasNext()) { List list = (List) it.next(); int type = ((Integer) list.get(0)).intValue(); // If type is 2, then we've got a dNSName if (type == 2) { String s = (String) list.get(1); subjectAltList.add(s); } } } if (!subjectAltList.isEmpty()) { String[] subjectAlts = new String[subjectAltList.size()]; subjectAltList.toArray(subjectAlts); return subjectAlts; } else { return null; } }
/** Read an existing PKCS#7 object from a DER encoded byte array */ public PKCS7SignedData(byte[] in, String provider) throws SecurityException, CRLException, InvalidKeyException, NoSuchProviderException, NoSuchAlgorithmException { ASN1InputStream din = new ASN1InputStream(new ByteArrayInputStream(in)); // // Basic checks to make sure it's a PKCS#7 SignedData Object // DERObject pkcs; try { pkcs = din.readObject(); } catch (IOException e) { throw new SecurityException("can't decode PKCS7SignedData object"); } if (!(pkcs instanceof ASN1Sequence)) { throw new SecurityException("Not a valid PKCS#7 object - not a sequence"); } ContentInfo content = ContentInfo.getInstance(pkcs); if (!content.getContentType().equals(signedData)) { throw new SecurityException( "Not a valid PKCS#7 signed-data object - wrong header " + content.getContentType().getId()); } SignedData data = SignedData.getInstance(content.getContent()); certs = new ArrayList(); if (data.getCertificates() != null) { Enumeration ec = ASN1Set.getInstance(data.getCertificates()).getObjects(); while (ec.hasMoreElements()) { try { certs.add( new X509CertificateObject(X509CertificateStructure.getInstance(ec.nextElement()))); } catch (CertificateParsingException e) { throw new SecurityException(e.toString()); } } } crls = new ArrayList(); if (data.getCRLs() != null) { Enumeration ec = ASN1Set.getInstance(data.getCRLs()).getObjects(); while (ec.hasMoreElements()) { crls.add(new X509CRLObject(CertificateList.getInstance(ec.nextElement()))); } } version = data.getVersion().getValue().intValue(); // // Get the digest algorithm // digestalgos = new HashSet(); Enumeration e = data.getDigestAlgorithms().getObjects(); while (e.hasMoreElements()) { ASN1Sequence s = (ASN1Sequence) e.nextElement(); DERObjectIdentifier o = (DERObjectIdentifier) s.getObjectAt(0); digestalgos.add(o.getId()); } // // Get the SignerInfo // ASN1Set signerinfos = data.getSignerInfos(); if (signerinfos.size() != 1) { throw new SecurityException( "This PKCS#7 object has multiple SignerInfos - only one is supported at this time"); } SignerInfo signerInfo = SignerInfo.getInstance(signerinfos.getObjectAt(0)); signerversion = signerInfo.getVersion().getValue().intValue(); IssuerAndSerialNumber isAnds = signerInfo.getIssuerAndSerialNumber(); // // Get the signing certificate // BigInteger serialNumber = isAnds.getCertificateSerialNumber().getValue(); X509Principal issuer = new X509Principal(isAnds.getName()); for (Iterator i = certs.iterator(); i.hasNext(); ) { X509Certificate cert = (X509Certificate) i.next(); if (serialNumber.equals(cert.getSerialNumber()) && issuer.equals(cert.getIssuerDN())) { signCert = cert; break; } } if (signCert == null) { throw new SecurityException( "Can't find signing certificate with serial " + serialNumber.toString(16)); } digestAlgorithm = signerInfo.getDigestAlgorithm().getObjectId().getId(); digest = signerInfo.getEncryptedDigest().getOctets(); digestEncryptionAlgorithm = signerInfo.getDigestEncryptionAlgorithm().getObjectId().getId(); sig = Signature.getInstance(getDigestAlgorithm(), provider); sig.initVerify(signCert.getPublicKey()); }
} else { ContentInfo var19 = ContentInfo.getInstance(var16); DERObjectIdentifier var20 = var19.getContentType(); DERObjectIdentifier var21 = signedData; if(!var20.equals(var21)) { StringBuilder var22 = (new StringBuilder()).append("Not a valid PKCS#7 signed-data object - wrong header "); String var23 = var19.getContentType().getId(); String var24 = var22.append(var23).toString(); throw new SecurityException(var24); } else { SignedData var25 = SignedData.getInstance(var19.getContent()); ArrayList var26 = new ArrayList(); this.certs = var26; Enumeration var27; if(var25.getCertificates() != null) { var27 = ASN1Set.getInstance(var25.getCertificates()).getObjects(); while(var27.hasMoreElements()) { try { Collection var28 = this.certs; X509CertificateStructure var29 = X509CertificateStructure.getInstance(var27.nextElement()); X509CertificateObject var30 = new X509CertificateObject(var29); var28.add(var30); } catch (CertificateParsingException var80) { String var32 = var80.toString(); throw new SecurityException(var32); } } } ArrayList var33 = new ArrayList(); this.crls = var33; if(var25.getCRLs() != null) { var27 = ASN1Set.getInstance(var25.getCRLs()).getObjects(); while(var27.hasMoreElements()) { Collection var34 = this.crls; CertificateList var35 = CertificateList.getInstance(var27.nextElement()); X509CRLObject var36 = new X509CRLObject(var35); var34.add(var36); } } int var38 = var25.getVersion().getValue().intValue(); this.version = var38; HashSet var39 = new HashSet(); this.digestalgos = var39; Enumeration var40 = var25.getDigestAlgorithms().getObjects(); while(var40.hasMoreElements()) { ASN1Sequence var41 = (ASN1Sequence)var40.nextElement(); byte var42 = 0; DERObjectIdentifier var43 = (DERObjectIdentifier)var41.getObjectAt(var42); Set var44 = this.digestalgos; String var45 = var43.getId(); var44.add(var45); } ASN1Set var47 = var25.getSignerInfos(); int var48 = var47.size(); byte var49 = 1; if(var48 != var49) { throw new SecurityException("This PKCS#7 object has multiple SignerInfos - only one is supported at this time"); } else { SignerInfo var50 = SignerInfo.getInstance(var47.getObjectAt(0)); int var51 = var50.getVersion().getValue().intValue(); this.signerversion = var51; IssuerAndSerialNumber var52 = var50.getIssuerAndSerialNumber(); BigInteger var53 = var52.getCertificateSerialNumber().getValue(); X509Principal var54 = new X509Principal; X509Name var55 = var52.getName(); var54.<init>(var55); Iterator var58 = this.certs.iterator(); while(var58.hasNext()) { X509Certificate var59 = (X509Certificate)var58.next(); BigInteger var60 = var59.getSerialNumber(); if(var53.equals(var60)) { Principal var63 = var59.getIssuerDN(); if(var54.equals(var63)) { this.signCert = var59; break; } } } if(this.signCert == null) { StringBuilder var67 = (new StringBuilder()).append("Can\'t find signing certificate with serial "); byte var69 = 16; String var70 = var53.toString(var69); String var71 = var67.append(var70).toString(); throw new SecurityException(var71); } else { String var72 = var50.getDigestAlgorithm().getObjectId().getId(); this.digestAlgorithm = var72; byte[] var73 = var50.getEncryptedDigest().getOctets(); this.digest = var73; String var74 = var50.getDigestEncryptionAlgorithm().getObjectId().getId(); this.digestEncryptionAlgorithm = var74; String var75 = this.getDigestAlgorithm(); Signature var77 = Signature.getInstance(var75, var2); this.sig = var77; Signature var78 = this.sig; PublicKey var79 = this.signCert.getPublicKey(); var78.initVerify(var79); } }
@Override public SecurityKeyData processRegistrationResponse( RegistrationResponse registrationResponse, long currentTimeInMillis) throws U2FException { Log.info(">> processRegistrationResponse"); String sessionId = registrationResponse.getSessionId(); String clientDataBase64 = registrationResponse.getClientData(); String rawRegistrationDataBase64 = registrationResponse.getRegistrationData(); Log.info(">> rawRegistrationDataBase64: " + rawRegistrationDataBase64); EnrollSessionData sessionData = dataStore.getEnrollSessionData(sessionId); if (sessionData == null) { throw new U2FException("Unknown session_id"); } String appId = sessionData.getAppId(); String clientData = new String(Base64.decodeBase64(clientDataBase64)); byte[] rawRegistrationData = Base64.decodeBase64(rawRegistrationDataBase64); Log.info("-- Input --"); Log.info(" sessionId: " + sessionId); Log.info(" challenge: " + Hex.encodeHexString(sessionData.getChallenge())); Log.info(" accountName: " + sessionData.getAccountName()); Log.info(" clientData: " + clientData); Log.info(" rawRegistrationData: " + Hex.encodeHexString(rawRegistrationData)); RegisterResponse registerResponse = RawMessageCodec.decodeRegisterResponse(rawRegistrationData); byte[] userPublicKey = registerResponse.getUserPublicKey(); byte[] keyHandle = registerResponse.getKeyHandle(); X509Certificate attestationCertificate = registerResponse.getAttestationCertificate(); byte[] signature = registerResponse.getSignature(); List<Transports> transports = null; try { transports = U2fAttestation.Parse(attestationCertificate).getTransports(); } catch (CertificateParsingException e) { Log.warning("Could not parse transports extension " + e.getMessage()); } Log.info("-- Parsed rawRegistrationResponse --"); Log.info(" userPublicKey: " + Hex.encodeHexString(userPublicKey)); Log.info(" keyHandle: " + Hex.encodeHexString(keyHandle)); Log.info(" attestationCertificate: " + attestationCertificate.toString()); Log.info(" transports: " + transports); try { Log.info( " attestationCertificate bytes: " + Hex.encodeHexString(attestationCertificate.getEncoded())); } catch (CertificateEncodingException e) { throw new U2FException("Cannot encode certificate", e); } Log.info(" signature: " + Hex.encodeHexString(signature)); byte[] appIdSha256 = cryto.computeSha256(appId.getBytes()); byte[] clientDataSha256 = cryto.computeSha256(clientData.getBytes()); byte[] signedBytes = RawMessageCodec.encodeRegistrationSignedBytes( appIdSha256, clientDataSha256, keyHandle, userPublicKey); Set<X509Certificate> trustedCertificates = dataStore.getTrustedCertificates(); if (!trustedCertificates.contains(attestationCertificate)) { Log.warning("attestion cert is not trusted"); } verifyBrowserData( new JsonParser().parse(clientData), "navigator.id.finishEnrollment", sessionData); Log.info("Verifying signature of bytes " + Hex.encodeHexString(signedBytes)); if (!cryto.verifySignature(attestationCertificate, signedBytes, signature)) { throw new U2FException("Signature is invalid"); } // The first time we create the SecurityKeyData, we set the counter value to 0. // We don't actually know what the counter value of the real device is - but it will // be something bigger (or equal) to 0, so subsequent signatures will check out ok. SecurityKeyData securityKeyData = new SecurityKeyData( currentTimeInMillis, transports, keyHandle, userPublicKey, attestationCertificate, /* initial counter value */ 0); dataStore.addSecurityKeyData(sessionData.getAccountName(), securityKeyData); Log.info("<< processRegistrationResponse"); return securityKeyData; }