Warning: file_get_contents(/data/phpspider/zhask/data//catemap/9/java/335.json): failed to open stream: No such file or directory in /data/phpspider/zhask/libs/function.php on line 167

Warning: Invalid argument supplied for foreach() in /data/phpspider/zhask/libs/tag.function.php on line 1116

Notice: Undefined index: in /data/phpspider/zhask/libs/function.php on line 180

Warning: array_chunk() expects parameter 1 to be array, null given in /data/phpspider/zhask/libs/function.php on line 181

Warning: file_get_contents(/data/phpspider/zhask/data//catemap/8/redis/2.json): failed to open stream: No such file or directory in /data/phpspider/zhask/libs/function.php on line 167

Warning: Invalid argument supplied for foreach() in /data/phpspider/zhask/libs/tag.function.php on line 1116

Notice: Undefined index: in /data/phpspider/zhask/libs/function.php on line 180

Warning: array_chunk() expects parameter 1 to be array, null given in /data/phpspider/zhask/libs/function.php on line 181
使用Java Mail验证具有Outlook 2013签名的电子邮件_Java_Outlook_Jakarta Mail_Digital Signature_X509certificate - Fatal编程技术网

使用Java Mail验证具有Outlook 2013签名的电子邮件

使用Java Mail验证具有Outlook 2013签名的电子邮件,java,outlook,jakarta-mail,digital-signature,x509certificate,Java,Outlook,Jakarta Mail,Digital Signature,X509certificate,我发送一封带有签名的电子邮件到我的收件箱。然后我使用JavaMail接收邮件并验证签名。但始终存在错误消息“消息摘要属性值与计算值不匹配” org.bouncycastle.cms.CMSSignerDigestMismatchException: message-digest attribute value does not match calculated value at org.bouncycastle.cms.SignerInformation.doVerify(SignerInfor

我发送一封带有签名的电子邮件到我的收件箱。然后我使用JavaMail接收邮件并验证签名。但始终存在错误消息“消息摘要属性值与计算值不匹配”

org.bouncycastle.cms.CMSSignerDigestMismatchException: message-digest attribute value does not match calculated value
at org.bouncycastle.cms.SignerInformation.doVerify(SignerInformation.java:517)
at org.bouncycastle.cms.SignerInformation.verify(SignerInformation.java:601)
我用maven

这是我的密码:

    public static void receiveSignedMail(Message msg) throws MessagingException {
    try {
        SMIMESigned signed = new SMIMESigned((MimeMultipart) msg.getContent());
        if (isValid(signed)) {
            System.out.println("verification succeeded");
        } else {
            System.out.println("verification failed");
        }
        signed = new SMIMESigned((MimeMultipart) msg.getContent());
         MimeBodyPart content = signed.getContent();
         System.out.println("Content: " + content.getContent());
    } catch (Exception e) {
        e.printStackTrace(System.out);
    }
}

public static boolean isValid(CMSSignedData signedData) {
    try {
        SignerInformationStore signers = signedData.getSignerInfos();
        Iterator<SignerInformation> it = signers.getSigners().iterator();
        boolean verify = false;
        while (it.hasNext()) {
            SignerInformation signer = it.next();
            org.bouncycastle.util.Store store = (org.bouncycastle.util.Store) signedData.getCertificates();
            Collection certCollection = ((org.bouncycastle.util.Store) store).getMatches(signer.getSID());
            Iterator certIt = certCollection.iterator();
            X509CertificateHolder certHolder = (X509CertificateHolder) certIt.next();
            X509Certificate certificate = new JcaX509CertificateConverter().setProvider("BC").getCertificate(certHolder);
            verify = signer.verify(new JcaSimpleSignerInfoVerifierBuilder().setProvider("BC").build(certificate));
        }
        return verify;
    } catch (Exception e) {
        e.printStackTrace(System.out);
        return false;
    }
}

public static Folder getFolder(String folderName) {
    try {
        String host = "your mail server";
        boolean auth = true;
        /* You must use SSL for incoming mail, SSL ports are 993 for IMAP and 995 for POP3 */
        /* To support SSL, using protocl 'pop3s' or 'imaps' */
        String port = "993";
        String receivingProtocol = "imaps";
        String username = "your email address";
        String password = "your email password";

        Properties props = System.getProperties();
        props.put("mail.smtp.host", host);
        props.put("mail.smtp.port", port);
        props.put("mail.smtp.auth", auth);
        props.put("mail.store.protocol", receivingProtocol);
        Session session = Session.getDefaultInstance(props, null);
        Store store = session.getStore(receivingProtocol);
        store.connect(host, username, password);
        Folder folder = store.getFolder(folderName);
        folder.open(Folder.READ_WRITE);
        return folder;
    } catch (Exception e) {
        e.printStackTrace(System.out);
        return null;
    }
}
public static void receiveSignedMail(Message msg)抛出消息异常{
试一试{
SMIMESigned signed=新SMIMESigned((MimeMultipart)msg.getContent());
如果(有效(签名)){
System.out.println(“验证成功”);
}否则{
System.out.println(“验证失败”);
}
signed=新SMIMESigned((MimeMultipart)msg.getContent());
MimeBodyPart content=signed.getContent();
System.out.println(“内容:+Content.getContent());
}捕获(例外e){
e、 printStackTrace(系统输出);
}
}
公共静态布尔值有效(CMSSignedData signedData){
试一试{
SignerInformationStore signers=signedData.getSignerInfos();
迭代器it=signers.getSigners().Iterator();
布尔验证=假;
while(it.hasNext()){
SignerInformation signer=it.next();
org.bouncycastle.util.Store Store=(org.bouncycastle.util.Store)signedData.getCertificates();
集合certCollection=((org.bouncycastle.util.Store)Store).getMatches(signer.getSID());
迭代器certIt=certCollection.Iterator();
X509CertificateHolder证书持有者=(X509CertificateHolder)certIt.next();
X509Certificate certificate=new JcaX509CertificateConverter().setProvider(“BC”).getCertificate(certHolder);
verify=signer.verify(新的JcaSimpleSignerInfoVerifierBuilder().setProvider(“BC”).build(证书));
}
返回验证;
}捕获(例外e){
e、 printStackTrace(系统输出);
返回false;
}
}
公共静态文件夹getFolder(字符串folderName){
试一试{
String host=“您的邮件服务器”;
布尔auth=true;
/*您必须对传入邮件使用SSL,对于IMAP,SSL端口为993;对于POP3,SSL端口为995*/
/*要支持SSL,请使用protocl“POP3”或“imaps”*/
字符串端口=“993”;
字符串接收协议=“imaps”;
String username=“您的电子邮件地址”;
String password=“您的电子邮件密码”;
Properties props=System.getProperties();
props.put(“mail.smtp.host”,host);
props.put(“mail.smtp.port”,port);
put(“mail.smtp.auth”,auth);
props.put(“mail.store.protocol”,receivingProtocol);
Session Session=Session.getDefaultInstance(props,null);
Store Store=session.getStore(receivingProtocol);
store.connect(主机、用户名、密码);
Folder Folder=store.getFolder(folderName);
文件夹。打开(文件夹。读写);
返回文件夹;
}捕获(例外e){
e、 printStackTrace(系统输出);
返回null;
}
}
以及运行它的主要方法

public static void main(String args[]) {
    Security.addProvider(new org.bouncycastle.jce.provider.BouncyCastleProvider());
    try {
        String inbox = "Your Inbox";
        Folder folder = getFolder(inbox);
        SearchTerm st = new OrTerm(new FromStringTerm("search condition"), new SubjectTerm("search condition"));
        Message[] messages = folder.search(st);
        int mailCounts = messages.length;
        System.out.println("Found: " + mailCounts + " mails matched with the condition.");

        if (messages.length == 0) {
            System.out.println("No Message!");
        }
        for (int i = 0; i < messages.length; i++) {
            System.out.println("the " + (i + 1) + " mail" + "------------------------------------------------");
            MimeMessage mail = (MimeMessage) messages[i];
            String out_from = ((InternetAddress) messages[i].getFrom()[0]).getAddress();
            System.out.println("From:" + out_from);
            System.out.println("Subject:" + messages[i].getSubject());
            System.out.println("Type: " + mail.getContentType());
            if (mail.isMimeType("multipart/signed")) {
                System.out.println("a signed mail");
                receiveSignedMail(mail);
            }
        }
        folder.close(true);
    } catch (Exception e) {
        e.printStackTrace(System.out);
    }
}
publicstaticvoidmain(字符串参数[]){
addProvider(新org.bouncycastle.jce.provider.BouncyCastleProvider());
试一试{
String inbox=“您的收件箱”;
Folder Folder=getFolder(收件箱);
SearchTerm st=新的OrTerm(新的FromStringTerm(“搜索条件”)、新的SubjectTerm(“搜索条件”);
Message[]messages=folder.search(st);
int mailCounts=messages.length;
System.out.println(“找到:“+mailCounts+”与条件匹配的邮件”);
如果(messages.length==0){
System.out.println(“没有消息!”);
}
for(int i=0;i
我与所有其他电子邮件客户端(Thunderbird、Outlook等)有相同的问题,但我能够解决它。我认为这个问题是由javax.mail库中的一个bug引起的

我使用以下Maven依赖项:

<dependency>
    <groupId>com.sun.mail</groupId>
    <artifactId>javax.mail</artifactId>
    <version>1.6.2</version>
</dependency>

<dependency>
     <groupId>org.bouncycastle</groupId>
     <artifactId>bcprov-jdk15on</artifactId>
     <version>1.62</version>
</dependency>

<dependency>
    <groupId>org.bouncycastle</groupId>
    <artifactId>bcmail-jdk15on</artifactId>
    <version>1.62</version>
</dependency>
现在,您将迭代这个数组并分别处理每条消息。这意味着,您正在直接使用消息对象

但是,如果要使用Bouncy Castle验证邮件的签名,则需要使用mimessage对象(请参阅Bouncy Castle中的代码;代码行93)

要将消息转换为mimessage,通常需要以以下方式强制转换对象:

MimeMessage mimeMsg = (MimeMessage) message;
但由于某些原因,这无法正常工作,因此我在稍后使用Bouncy Castle验证电子邮件签名时遇到以下异常:
org.bounchycastle.cms.CMSSignerDigestMismatchException:message digest属性值与计算值不匹配

我所做的变通方法是,使用MimeMessage构造函数复制已经转换的MimeMessage对象

所以这解决了我的问题

MimeMessage mimeMsg = new MimeMessage((MimeMessage) message);
以下是完整的工作代码

Message message = // get Message from folder...
MimeMessage mimeMsg = new MimeMessage((MimeMessage) message);
boolean emailSignatureValid = verifySignature(mimeMsg);

 // code from Bouncy Castle
 public boolean verifySignature(MimeMessage signedMimeMessage) {
    try {
        if (signedMimeMessage.isMimeType("multipart/signed")) {
            SMIMESignedParser s = new SMIMESignedParser(new JcaDigestCalculatorProviderBuilder().build(), (MimeMultipart) signedMimeMessage.getContent());
            return verify(s);
        } else if (signedMimeMessage.isMimeType("application/pkcs7-mime")) {
            SMIMESignedParser s = new SMIMESignedParser(new JcaDigestCalculatorProviderBuilder().build(), signedMimeMessage);
            return verify(s);
        } else {
            throw new IllegalArgumentException("This mimeMessage is not signed: " + EmailPrinter.printMessage(signedMimeMessage));
        }
    } catch (Exception e) {
        log.error("Could not verify signature of mimeMessage", e);
        return false;
    }
}

 // code from Bouncy Castle
 private static boolean verify(SMIMESignedParser s) throws Exception {

    Store certs = s.getCertificates();
    SignerInformationStore signers = s.getSignerInfos();
    Collection c = signers.getSigners();
    Iterator it = c.iterator();
    while (it.hasNext()) {
        SignerInformation signer = (SignerInformation) it.next();
        Collection certCollection = certs.getMatches(signer.getSID());
        Iterator certIt = certCollection.iterator();
        X509Certificate cert = new JcaX509CertificateConverter().setProvider(BC).getCertificate((X509CertificateHolder) certIt.next());
        try {
            return signer.verify(new JcaSimpleSignerInfoVerifierBuilder().setProvider(BC).build(cert));
        } catch (Exception e) {
            log.error("Error occured during verification",e);
        }
    }

    return false;
}
我知道这是一个奇怪的解决办法,但这是唯一的办法,我可以解决这个问题。我希望你也觉得它有用

干杯


BeeDeveloper

能否显示代码中的哪一行
MimeMessage mimeMsg = (MimeMessage) message;
MimeMessage mimeMsg = new MimeMessage((MimeMessage) message);
Message message = // get Message from folder...
MimeMessage mimeMsg = new MimeMessage((MimeMessage) message);
boolean emailSignatureValid = verifySignature(mimeMsg);

 // code from Bouncy Castle
 public boolean verifySignature(MimeMessage signedMimeMessage) {
    try {
        if (signedMimeMessage.isMimeType("multipart/signed")) {
            SMIMESignedParser s = new SMIMESignedParser(new JcaDigestCalculatorProviderBuilder().build(), (MimeMultipart) signedMimeMessage.getContent());
            return verify(s);
        } else if (signedMimeMessage.isMimeType("application/pkcs7-mime")) {
            SMIMESignedParser s = new SMIMESignedParser(new JcaDigestCalculatorProviderBuilder().build(), signedMimeMessage);
            return verify(s);
        } else {
            throw new IllegalArgumentException("This mimeMessage is not signed: " + EmailPrinter.printMessage(signedMimeMessage));
        }
    } catch (Exception e) {
        log.error("Could not verify signature of mimeMessage", e);
        return false;
    }
}

 // code from Bouncy Castle
 private static boolean verify(SMIMESignedParser s) throws Exception {

    Store certs = s.getCertificates();
    SignerInformationStore signers = s.getSignerInfos();
    Collection c = signers.getSigners();
    Iterator it = c.iterator();
    while (it.hasNext()) {
        SignerInformation signer = (SignerInformation) it.next();
        Collection certCollection = certs.getMatches(signer.getSID());
        Iterator certIt = certCollection.iterator();
        X509Certificate cert = new JcaX509CertificateConverter().setProvider(BC).getCertificate((X509CertificateHolder) certIt.next());
        try {
            return signer.verify(new JcaSimpleSignerInfoVerifierBuilder().setProvider(BC).build(cert));
        } catch (Exception e) {
            log.error("Error occured during verification",e);
        }
    }

    return false;
}