Search in sources :

Example 1 with SignerInformationVerifier

use of org.bouncycastle.cms.SignerInformationVerifier in project jmeter by apache.

the class SMIMEAssertion method verifySignature.

private static AssertionResult verifySignature(SMIMEAssertionTestElement testElement, SMIMESignedParser s, String name) throws CMSException {
    AssertionResult res = new AssertionResult(name);
    try {
        Store certs = s.getCertificates();
        SignerInformationStore signers = s.getSignerInfos();
        Iterator<?> signerIt = signers.getSigners().iterator();
        if (signerIt.hasNext()) {
            SignerInformation signer = (SignerInformation) signerIt.next();
            Iterator<?> certIt = certs.getMatches(signer.getSID()).iterator();
            if (certIt.hasNext()) {
                // the signer certificate
                X509CertificateHolder cert = (X509CertificateHolder) certIt.next();
                if (testElement.isVerifySignature()) {
                    SignerInformationVerifier verifier = null;
                    try {
                        verifier = new JcaSimpleSignerInfoVerifierBuilder().setProvider("BC").build(cert);
                    } catch (OperatorCreationException e) {
                        log.error("Can't create a provider.", e);
                    }
                    if (verifier == null || !signer.verify(verifier)) {
                        res.setFailure(true);
                        res.setFailureMessage("Signature is invalid");
                    }
                }
                if (testElement.isSignerCheckConstraints()) {
                    StringBuilder failureMessage = new StringBuilder();
                    String serial = testElement.getSignerSerial();
                    if (!JOrphanUtils.isBlank(serial)) {
                        BigInteger serialNbr = readSerialNumber(serial);
                        if (!serialNbr.equals(cert.getSerialNumber())) {
                            res.setFailure(true);
                            failureMessage.append("Serial number ").append(serialNbr).append(" does not match serial from signer certificate: ").append(cert.getSerialNumber()).append("\n");
                        }
                    }
                    String email = testElement.getSignerEmail();
                    if (!JOrphanUtils.isBlank(email)) {
                        List<String> emailFromCert = getEmailFromCert(cert);
                        if (!emailFromCert.contains(email)) {
                            res.setFailure(true);
                            failureMessage.append("Email address \"").append(email).append("\" not present in signer certificate\n");
                        }
                    }
                    String subject = testElement.getSignerDn();
                    if (subject.length() > 0) {
                        final X500Name certPrincipal = cert.getSubject();
                        log.debug("DN from cert: {}", certPrincipal);
                        X500Name principal = new X500Name(subject);
                        log.debug("DN from assertion: {}", principal);
                        if (!principal.equals(certPrincipal)) {
                            res.setFailure(true);
                            failureMessage.append("Distinguished name of signer certificate does not match \"").append(subject).append("\"\n");
                        }
                    }
                    String issuer = testElement.getIssuerDn();
                    if (issuer.length() > 0) {
                        final X500Name issuerX500Name = cert.getIssuer();
                        log.debug("IssuerDN from cert: {}", issuerX500Name);
                        X500Name principal = new X500Name(issuer);
                        log.debug("IssuerDN from assertion: {}", principal);
                        if (!principal.equals(issuerX500Name)) {
                            res.setFailure(true);
                            failureMessage.append("Issuer distinguished name of signer certificate does not match \"").append(subject).append("\"\n");
                        }
                    }
                    if (failureMessage.length() > 0) {
                        res.setFailureMessage(failureMessage.toString());
                    }
                }
                if (testElement.isSignerCheckByFile()) {
                    CertificateFactory cf = CertificateFactory.getInstance("X.509");
                    try (InputStream fis = new FileInputStream(testElement.getSignerCertFile());
                        InputStream bis = new BufferedInputStream(fis)) {
                        X509CertificateHolder certFromFile = new JcaX509CertificateHolder((X509Certificate) cf.generateCertificate(bis));
                        if (!certFromFile.equals(cert)) {
                            res.setFailure(true);
                            res.setFailureMessage("Signer certificate does not match certificate " + testElement.getSignerCertFile());
                        }
                    } catch (IOException e) {
                        if (log.isDebugEnabled()) {
                            log.debug("Could not read cert file {}", testElement.getSignerCertFile(), e);
                        }
                        res.setFailure(true);
                        res.setFailureMessage("Could not read certificate file " + testElement.getSignerCertFile());
                    }
                }
            } else {
                res.setFailure(true);
                res.setFailureMessage("No signer certificate found in signature");
            }
        }
        // TODO support multiple signers
        if (signerIt.hasNext()) {
            log.warn("SMIME message contains multiple signers! Checking multiple signers is not supported.");
        }
    } catch (GeneralSecurityException e) {
        log.error(e.getMessage(), e);
        res.setError(true);
        res.setFailureMessage(e.getMessage());
    }
    return res;
}
Also used : BufferedInputStream(java.io.BufferedInputStream) ByteArrayInputStream(java.io.ByteArrayInputStream) FileInputStream(java.io.FileInputStream) InputStream(java.io.InputStream) GeneralSecurityException(java.security.GeneralSecurityException) Store(org.bouncycastle.util.Store) SignerInformationStore(org.bouncycastle.cms.SignerInformationStore) SignerInformation(org.bouncycastle.cms.SignerInformation) JcaSimpleSignerInfoVerifierBuilder(org.bouncycastle.cms.jcajce.JcaSimpleSignerInfoVerifierBuilder) X500Name(org.bouncycastle.asn1.x500.X500Name) IOException(java.io.IOException) CertificateFactory(java.security.cert.CertificateFactory) JcaX509CertificateHolder(org.bouncycastle.cert.jcajce.JcaX509CertificateHolder) FileInputStream(java.io.FileInputStream) SignerInformationStore(org.bouncycastle.cms.SignerInformationStore) BufferedInputStream(java.io.BufferedInputStream) X509CertificateHolder(org.bouncycastle.cert.X509CertificateHolder) JcaX509CertificateHolder(org.bouncycastle.cert.jcajce.JcaX509CertificateHolder) BigInteger(java.math.BigInteger) SignerInformationVerifier(org.bouncycastle.cms.SignerInformationVerifier) OperatorCreationException(org.bouncycastle.operator.OperatorCreationException)

Example 2 with SignerInformationVerifier

use of org.bouncycastle.cms.SignerInformationVerifier in project poi by apache.

the class TSPTimeStampService method timeStamp.

@SuppressWarnings("unchecked")
public byte[] timeStamp(byte[] data, RevocationData revocationData) throws Exception {
    // digest the message
    MessageDigest messageDigest = CryptoFunctions.getMessageDigest(signatureConfig.getTspDigestAlgo());
    byte[] digest = messageDigest.digest(data);
    // generate the TSP request
    BigInteger nonce = new BigInteger(128, new SecureRandom());
    TimeStampRequestGenerator requestGenerator = new TimeStampRequestGenerator();
    requestGenerator.setCertReq(true);
    String requestPolicy = signatureConfig.getTspRequestPolicy();
    if (requestPolicy != null) {
        requestGenerator.setReqPolicy(new ASN1ObjectIdentifier(requestPolicy));
    }
    ASN1ObjectIdentifier digestAlgoOid = mapDigestAlgoToOID(signatureConfig.getTspDigestAlgo());
    TimeStampRequest request = requestGenerator.generate(digestAlgoOid, digest, nonce);
    byte[] encodedRequest = request.getEncoded();
    // create the HTTP POST request
    Proxy proxy = Proxy.NO_PROXY;
    if (signatureConfig.getProxyUrl() != null) {
        URL proxyUrl = new URL(signatureConfig.getProxyUrl());
        String host = proxyUrl.getHost();
        int port = proxyUrl.getPort();
        proxy = new Proxy(Proxy.Type.HTTP, new InetSocketAddress(InetAddress.getByName(host), (port == -1 ? 80 : port)));
    }
    HttpURLConnection huc = (HttpURLConnection) new URL(signatureConfig.getTspUrl()).openConnection(proxy);
    if (signatureConfig.getTspUser() != null) {
        String userPassword = signatureConfig.getTspUser() + ":" + signatureConfig.getTspPass();
        String encoding = DatatypeConverter.printBase64Binary(userPassword.getBytes(Charset.forName("iso-8859-1")));
        huc.setRequestProperty("Authorization", "Basic " + encoding);
    }
    huc.setRequestMethod("POST");
    huc.setConnectTimeout(20000);
    huc.setReadTimeout(20000);
    // also sets method to POST.
    huc.setDoOutput(true);
    huc.setRequestProperty("User-Agent", signatureConfig.getUserAgent());
    huc.setRequestProperty("Content-Type", signatureConfig.isTspOldProtocol() ? "application/timestamp-request" : // "; charset=ISO-8859-1");
    "application/timestamp-query");
    OutputStream hucOut = huc.getOutputStream();
    hucOut.write(encodedRequest);
    // invoke TSP service
    huc.connect();
    int statusCode = huc.getResponseCode();
    if (statusCode != 200) {
        LOG.log(POILogger.ERROR, "Error contacting TSP server ", signatureConfig.getTspUrl() + ", had status code " + statusCode + "/" + huc.getResponseMessage());
        throw new IOException("Error contacting TSP server " + signatureConfig.getTspUrl() + ", had status code " + statusCode + "/" + huc.getResponseMessage());
    }
    // HTTP input validation
    String contentType = huc.getHeaderField("Content-Type");
    if (null == contentType) {
        throw new RuntimeException("missing Content-Type header");
    }
    ByteArrayOutputStream bos = new ByteArrayOutputStream();
    IOUtils.copy(huc.getInputStream(), bos);
    LOG.log(POILogger.DEBUG, "response content: ", HexDump.dump(bos.toByteArray(), 0, 0));
    if (!contentType.startsWith(signatureConfig.isTspOldProtocol() ? "application/timestamp-response" : "application/timestamp-reply")) {
        throw new RuntimeException("invalid Content-Type: " + contentType + // dump the first few bytes
        ": " + HexDump.dump(bos.toByteArray(), 0, 0, 200));
    }
    if (bos.size() == 0) {
        throw new RuntimeException("Content-Length is zero");
    }
    // TSP response parsing and validation
    TimeStampResponse timeStampResponse = new TimeStampResponse(bos.toByteArray());
    timeStampResponse.validate(request);
    if (0 != timeStampResponse.getStatus()) {
        LOG.log(POILogger.DEBUG, "status: " + timeStampResponse.getStatus());
        LOG.log(POILogger.DEBUG, "status string: " + timeStampResponse.getStatusString());
        PKIFailureInfo failInfo = timeStampResponse.getFailInfo();
        if (null != failInfo) {
            LOG.log(POILogger.DEBUG, "fail info int value: " + failInfo.intValue());
            if (/*PKIFailureInfo.unacceptedPolicy*/
            (1 << 8) == failInfo.intValue()) {
                LOG.log(POILogger.DEBUG, "unaccepted policy");
            }
        }
        throw new RuntimeException("timestamp response status != 0: " + timeStampResponse.getStatus());
    }
    TimeStampToken timeStampToken = timeStampResponse.getTimeStampToken();
    SignerId signerId = timeStampToken.getSID();
    BigInteger signerCertSerialNumber = signerId.getSerialNumber();
    X500Name signerCertIssuer = signerId.getIssuer();
    LOG.log(POILogger.DEBUG, "signer cert serial number: " + signerCertSerialNumber);
    LOG.log(POILogger.DEBUG, "signer cert issuer: " + signerCertIssuer);
    // TSP signer certificates retrieval
    Collection<X509CertificateHolder> certificates = timeStampToken.getCertificates().getMatches(null);
    X509CertificateHolder signerCert = null;
    Map<X500Name, X509CertificateHolder> certificateMap = new HashMap<X500Name, X509CertificateHolder>();
    for (X509CertificateHolder certificate : certificates) {
        if (signerCertIssuer.equals(certificate.getIssuer()) && signerCertSerialNumber.equals(certificate.getSerialNumber())) {
            signerCert = certificate;
        }
        certificateMap.put(certificate.getSubject(), certificate);
    }
    // TSP signer cert path building
    if (signerCert == null) {
        throw new RuntimeException("TSP response token has no signer certificate");
    }
    List<X509Certificate> tspCertificateChain = new ArrayList<X509Certificate>();
    JcaX509CertificateConverter x509converter = new JcaX509CertificateConverter();
    x509converter.setProvider("BC");
    X509CertificateHolder certificate = signerCert;
    do {
        LOG.log(POILogger.DEBUG, "adding to certificate chain: " + certificate.getSubject());
        tspCertificateChain.add(x509converter.getCertificate(certificate));
        if (certificate.getSubject().equals(certificate.getIssuer())) {
            break;
        }
        certificate = certificateMap.get(certificate.getIssuer());
    } while (null != certificate);
    // verify TSP signer signature
    X509CertificateHolder holder = new X509CertificateHolder(tspCertificateChain.get(0).getEncoded());
    DefaultCMSSignatureAlgorithmNameGenerator nameGen = new DefaultCMSSignatureAlgorithmNameGenerator();
    DefaultSignatureAlgorithmIdentifierFinder sigAlgoFinder = new DefaultSignatureAlgorithmIdentifierFinder();
    DefaultDigestAlgorithmIdentifierFinder hashAlgoFinder = new DefaultDigestAlgorithmIdentifierFinder();
    BcDigestCalculatorProvider calculator = new BcDigestCalculatorProvider();
    BcRSASignerInfoVerifierBuilder verifierBuilder = new BcRSASignerInfoVerifierBuilder(nameGen, sigAlgoFinder, hashAlgoFinder, calculator);
    SignerInformationVerifier verifier = verifierBuilder.build(holder);
    timeStampToken.validate(verifier);
    // verify TSP signer certificate
    if (signatureConfig.getTspValidator() != null) {
        signatureConfig.getTspValidator().validate(tspCertificateChain, revocationData);
    }
    LOG.log(POILogger.DEBUG, "time-stamp token time: " + timeStampToken.getTimeStampInfo().getGenTime());
    return timeStampToken.getEncoded();
}
Also used : DefaultCMSSignatureAlgorithmNameGenerator(org.bouncycastle.cms.DefaultCMSSignatureAlgorithmNameGenerator) HashMap(java.util.HashMap) InetSocketAddress(java.net.InetSocketAddress) ByteArrayOutputStream(java.io.ByteArrayOutputStream) OutputStream(java.io.OutputStream) ArrayList(java.util.ArrayList) X500Name(org.bouncycastle.asn1.x500.X500Name) DefaultDigestAlgorithmIdentifierFinder(org.bouncycastle.operator.DefaultDigestAlgorithmIdentifierFinder) URL(java.net.URL) TimeStampResponse(org.bouncycastle.tsp.TimeStampResponse) Proxy(java.net.Proxy) HttpURLConnection(java.net.HttpURLConnection) JcaX509CertificateConverter(org.bouncycastle.cert.jcajce.JcaX509CertificateConverter) MessageDigest(java.security.MessageDigest) SignerInformationVerifier(org.bouncycastle.cms.SignerInformationVerifier) BcDigestCalculatorProvider(org.bouncycastle.operator.bc.BcDigestCalculatorProvider) SecureRandom(java.security.SecureRandom) IOException(java.io.IOException) ByteArrayOutputStream(java.io.ByteArrayOutputStream) TimeStampRequest(org.bouncycastle.tsp.TimeStampRequest) X509Certificate(java.security.cert.X509Certificate) DefaultSignatureAlgorithmIdentifierFinder(org.bouncycastle.operator.DefaultSignatureAlgorithmIdentifierFinder) PKIFailureInfo(org.bouncycastle.asn1.cmp.PKIFailureInfo) SignerId(org.bouncycastle.cms.SignerId) X509CertificateHolder(org.bouncycastle.cert.X509CertificateHolder) BigInteger(java.math.BigInteger) TimeStampRequestGenerator(org.bouncycastle.tsp.TimeStampRequestGenerator) BcRSASignerInfoVerifierBuilder(org.bouncycastle.cms.bc.BcRSASignerInfoVerifierBuilder) TimeStampToken(org.bouncycastle.tsp.TimeStampToken) ASN1ObjectIdentifier(org.bouncycastle.asn1.ASN1ObjectIdentifier)

Aggregations

IOException (java.io.IOException)2 BigInteger (java.math.BigInteger)2 X500Name (org.bouncycastle.asn1.x500.X500Name)2 X509CertificateHolder (org.bouncycastle.cert.X509CertificateHolder)2 SignerInformationVerifier (org.bouncycastle.cms.SignerInformationVerifier)2 BufferedInputStream (java.io.BufferedInputStream)1 ByteArrayInputStream (java.io.ByteArrayInputStream)1 ByteArrayOutputStream (java.io.ByteArrayOutputStream)1 FileInputStream (java.io.FileInputStream)1 InputStream (java.io.InputStream)1 OutputStream (java.io.OutputStream)1 HttpURLConnection (java.net.HttpURLConnection)1 InetSocketAddress (java.net.InetSocketAddress)1 Proxy (java.net.Proxy)1 URL (java.net.URL)1 GeneralSecurityException (java.security.GeneralSecurityException)1 MessageDigest (java.security.MessageDigest)1 SecureRandom (java.security.SecureRandom)1 CertificateFactory (java.security.cert.CertificateFactory)1 X509Certificate (java.security.cert.X509Certificate)1