0

我正在尝试将 PKCS11 keystone(智能卡)与 WSS4J 一起使用。我有从智能卡创建梯形失真的代码和另一个使用文件中的梯形失真通过 WSS4J 唱 SOAP 消息的代码。问题是如何“合并”它们。

PKCS11 密钥库:

    String pin = "1111";
    char[] pin_arr = pin.toCharArray();
    String pkcs11config = "name = SmartCard\n"  + "library = c:/windows/system32/aetpkss1.dll";
    byte[] pkcs11configBytes = pkcs11config.getBytes();
    ByteArrayInputStream configStream = new ByteArrayInputStream(pkcs11configBytes);
    Provider pkcs11Provider = new sun.security.pkcs11.SunPKCS11(configStream);
    Security.addProvider(pkcs11Provider);

    KeyStore smartCardKeyStore = KeyStore.getInstance("PKCS11");

    smartCardKeyStore.load(null, pin_arr);

WSS4J 签名代码:

    public Document signSOAPMessage(SOAPMessage soapEnvelope)
        throws SOAPException, TransformerException, WSSecurityException {
    Source src = soapEnvelope.getSOAPPart().getContent();
    TransformerFactory transformerFactory = TransformerFactory.newInstance();
    Transformer transformer = transformerFactory.newTransformer();
    DOMResult result = new DOMResult();
    transformer.transform(src, result);
    Document doc = (Document) result.getNode();

    final RequestData reqData = new RequestData();
    java.util.Map msgContext = new java.util.TreeMap();
    msgContext.put(WSHandlerConstants.ENABLE_SIGNATURE_CONFIRMATION, "true");
    msgContext.put(WSHandlerConstants.MUST_UNDERSTAND, "false");
    msgContext.put(WSHandlerConstants.SIG_PROP_FILE, "sender.properties");
    String bodyPart = "{Content}{}Body";
    String thumbprintPart = "{Element}{http://docs.oasis-open.org/wss/2004/01/oasis-200401-wss-wssecurity-secext-1.0.xsd}BinarySecurityToken";
    msgContext.put(WSHandlerConstants.SIGNATURE_PARTS, bodyPart + ";" + thumbprintPart);
    msgContext.put(WSHandlerConstants.ENABLE_SIGNATURE_CONFIRMATION, "true");


    // Set this property if you want client public key (X509 certificate) sent along with document
    // server will check signature using this public key
    msgContext.put(WSHandlerConstants.SIG_KEY_ID, "DirectReference");
    msgContext.put("password", "keystore");
    reqData.setMsgContext(msgContext);
    reqData.setUsername("clientca3");

    final java.util.List actions = new java.util.ArrayList();
    actions.add(new Integer(WSConstants.SIGN));
    CustomHandler handler = new CustomHandler();

    // sign document
    handler.send(WSConstants.SIGN, doc, reqData, actions, true);

    return doc;
}

最后是 sender.properties 文件:

    org.apache.ws.security.crypto.provider=org.apache.ws.security.components.crypto.Merlin
    org.apache.ws.security.crypto.merlin.keystore.type=jks
    org.apache.ws.security.crypto.merlin.keystore.password=keystore
    org.apache.ws.security.crypto.merlin.keystore.alias=clientca3
    org.apache.ws.security.crypto.merlin.keystore.file=C:/temp/keystore.jks
4

3 回答 3

0

这是我的做法:

  1. 创建新类 CryptoSmartCard,它是 Merlin 的副本并扩展 CryptoBase。新类和 Merlin 的区别在于方法 loadProperties(Properties properties, ClassLoader loader):

    public void loadProperties(Properties properties, ClassLoader loader)
        throws CredentialException, IOException {
    if (properties == null) {
        return;
    }
    this.properties = properties;
    //
    // Load the provider(s)
    //
    String provider = properties.getProperty(CRYPTO_KEYSTORE_PROVIDER);
    if (provider != null) {
        provider = provider.trim();
    }
    String certProvider = properties.getProperty(CRYPTO_CERT_PROVIDER);
    if (certProvider != null) {
        setCryptoProvider(certProvider);
    }
    //
    // Load the KeyStore
    //
    String alias = properties.getProperty(KEYSTORE_ALIAS);
    if (alias != null) {
        alias = alias.trim();
        defaultAlias = alias;
    }
    String keyStoreLocation = properties.getProperty(KEYSTORE_FILE);
    if (keyStoreLocation == null) {
        keyStoreLocation = properties.getProperty(OLD_KEYSTORE_FILE);
    }
    if (keyStoreLocation != null) {
        keyStoreLocation = keyStoreLocation.trim();
        InputStream is = loadInputStream(loader, keyStoreLocation);
    
        try {
            String passwd = properties.getProperty(KEYSTORE_PASSWORD, "security");
            if (passwd != null) {
                passwd = passwd.trim();
            }
            String type = properties.getProperty(KEYSTORE_TYPE, KeyStore.getDefaultType());
            if (type != null) {
                type = type.trim();
            }
    
            String pin = properties.getProperty(KEYSTORE_PRIVATE_PASSWORD);
            char[] pin_arr = pin.toCharArray();
            String pkcs11config = "name = SmartCard\n" + "library = " + properties.getProperty(KEYSTORE_FILE);
            byte[] pkcs11configBytes = pkcs11config.getBytes();
            ByteArrayInputStream configStream = new ByteArrayInputStream(pkcs11configBytes);
            Provider pkcs11Provider = new sun.security.pkcs11.SunPKCS11(configStream);
            try {
                Security.addProvider(pkcs11Provider);
    
                keystore = KeyStore.getInstance(type,pkcs11Provider);
    
                keystore.load(null, pin_arr);
    
    
            } catch (Exception ex) {
                // nothing
            }
            //keystore = load(is, passwd, provider, type);
            if (DO_DEBUG) {
                LOG.debug(
                        "The KeyStore " + keyStoreLocation + " of type " + type
                        + " has been loaded");
            }
            String privatePasswd = properties.getProperty(KEYSTORE_PRIVATE_PASSWORD);
            if (privatePasswd != null) {
                privatePasswordSet = true;
            }
        } finally {
            if (is != null) {
                is.close();
            }
        }
    } else {
        if (DO_DEBUG) {
            LOG.debug("The KeyStore is not loaded as KEYSTORE_FILE is null");
        }
    }
    
    //
    // Load the TrustStore
    //
    String trustStoreLocation = properties.getProperty(TRUSTSTORE_FILE);
    if (trustStoreLocation != null) {
        trustStoreLocation = trustStoreLocation.trim();
        InputStream is = loadInputStream(loader, trustStoreLocation);
    
        try {
            String passwd = properties.getProperty(TRUSTSTORE_PASSWORD, "changeit");
            if (passwd != null) {
                passwd = passwd.trim();
            }
            String type = properties.getProperty(TRUSTSTORE_TYPE, KeyStore.getDefaultType());
            if (type != null) {
                type = type.trim();
            }
            truststore = load(is, passwd, provider, type);
            if (DO_DEBUG) {
                LOG.debug(
                        "The TrustStore " + trustStoreLocation + " of type " + type
                        + " has been loaded");
            }
            loadCACerts = false;
        } finally {
            if (is != null) {
                is.close();
            }
        }
    } else {
        String loadCacerts = properties.getProperty(LOAD_CA_CERTS, "false");
        if (loadCacerts != null) {
            loadCacerts = loadCacerts.trim();
        }
        if (Boolean.valueOf(loadCacerts).booleanValue()) {
            String cacertsPath = System.getProperty("java.home") + "/lib/security/cacerts";
            if (cacertsPath != null) {
                cacertsPath = cacertsPath.trim();
            }
            InputStream is = new FileInputStream(cacertsPath);
            try {
                String cacertsPasswd = properties.getProperty(TRUSTSTORE_PASSWORD, "changeit");
                if (cacertsPasswd != null) {
                    cacertsPasswd = cacertsPasswd.trim();
                }
                truststore = load(is, cacertsPasswd, null, KeyStore.getDefaultType());
                if (DO_DEBUG) {
                    LOG.debug("CA certs have been loaded");
                }
                loadCACerts = true;
            } finally {
                if (is != null) {
                    is.close();
                }
            }
        }
    }
    //
    // Load the CRL file
    //
    String crlLocation = properties.getProperty(X509_CRL_FILE);
    if (crlLocation != null) {
        crlLocation = crlLocation.trim();
        InputStream is = loadInputStream(loader, crlLocation);
    
        try {
            CertificateFactory cf = getCertificateFactory();
            X509CRL crl = (X509CRL) cf.generateCRL(is);
    
            if (provider == null || provider.length() == 0) {
                crlCertStore =
                        CertStore.getInstance(
                        "Collection",
                        new CollectionCertStoreParameters(Collections.singletonList(crl)));
            } else {
                crlCertStore =
                        CertStore.getInstance(
                        "Collection",
                        new CollectionCertStoreParameters(Collections.singletonList(crl)),
                        provider);
            }
            if (DO_DEBUG) {
                LOG.debug(
                        "The CRL " + crlLocation + " has been loaded");
            }
        } catch (Exception e) {
            if (DO_DEBUG) {
                LOG.debug(e.getMessage(), e);
            }
            throw new CredentialException(CredentialException.IO_ERROR, "ioError00", e);
        } finally {
            if (is != null) {
                is.close();
            }
        }
    }
    

    }

该方法中只有以下几行发生了变化:

            String pin = properties.getProperty(KEYSTORE_PRIVATE_PASSWORD);
            char[] pin_arr = pin.toCharArray();
            String pkcs11config = "name = SmartCard\n" + "library = " + properties.getProperty(KEYSTORE_FILE);
            byte[] pkcs11configBytes = pkcs11config.getBytes();
            ByteArrayInputStream configStream = new ByteArrayInputStream(pkcs11configBytes);
            Provider pkcs11Provider = new sun.security.pkcs11.SunPKCS11(configStream);
            try {
                Security.addProvider(pkcs11Provider);

                keystore = KeyStore.getInstance(type,pkcs11Provider);

                keystore.load(null, pin_arr);


            } catch (Exception ex) {
                // nothing
            }
  1. 之后,我使用该类手动创建 Crypto 对象:

    加密crypto = new CryptoSmartCard(prop);

这是签名方法的代码:

   public Document signSOAPMessage3(SOAPMessage soapEnvelope)
        throws SOAPException, TransformerException, WSSecurityException, CredentialException, IOException {
    Source src = soapEnvelope.getSOAPPart().getContent();
    TransformerFactory transformerFactory = TransformerFactory.newInstance();
    Transformer transformer = transformerFactory.newTransformer();
    DOMResult result = new DOMResult();
    transformer.transform(src, result);
    Document doc = (Document) result.getNode();

    Properties prop = new Properties();
    try {
        InputStream input = new FileInputStream("sender.properties");
        prop.load(input);
    } catch (IOException ex) {
        Logger.getLogger(TestSignWS1.class.getName()).log(Level.SEVERE, null, ex);
    }

    Crypto crypto = new CryptoSmartCard(prop);

    final RequestData reqData = new RequestData();
    java.util.Map msgContext = new java.util.TreeMap();
    //msgContext.put(WSHandlerConstants.ENABLE_SIGNATURE_CONFIRMATION, "true");
    msgContext.put(WSHandlerConstants.MUST_UNDERSTAND, "false");
    //msgContext.put(WSHandlerConstants.SIG_PROP_FILE, "sender.properties");
    String bodyPart = "{Content}{}Body";
    String thumbprintPart = "{Element}{http://docs.oasis-open.org/wss/2004/01/oasis-200401-wss-wssecurity-secext-1.0.xsd}BinarySecurityToken";
    msgContext.put(WSHandlerConstants.SIGNATURE_PARTS, thumbprintPart + ";" + bodyPart);
    msgContext.put(WSHandlerConstants.IS_BSP_COMPLIANT, "false");
    msgContext.put(WSHandlerConstants.SIG_ALGO, WSConstants.RSA_SHA1);


    // Set this property if you want client public key (X509 certificate) sent along with document
    // server will check signature using this public key
    msgContext.put(WSHandlerConstants.SIG_KEY_ID, "DirectReference");
    msgContext.put("password", prop.getProperty(KEYSTORE_PRIVATE_PASSWORD));
    reqData.setMsgContext(msgContext);
    reqData.setUsername(crypto.getDefaultX509Identifier());
    reqData.setUseSingleCert(true);
    reqData.setSigCrypto(crypto);

    final java.util.List actions = new java.util.ArrayList();
    actions.add(new Integer(WSConstants.SIGN));
    CustomHandler handler = new CustomHandler();

    // sign document
    handler.send(WSConstants.SIGN, doc, reqData, actions, true);

    return doc;
}

和配置文件:

org.apache.ws.security.crypto.provider=hgaa.ws.crypto.CryptoSmartCard
org.apache.ws.security.crypto.merlin.keystore.provider=SunPKCS11
org.apache.ws.security.crypto.merlin.keystore.type=PKCS11
org.apache.ws.security.crypto.merlin.keystore.file=c:/windows/system32/aetpkss1.dll
org.apache.ws.security.crypto.merlin.keystore.private.password=xxxx
于 2014-05-07T08:04:57.337 回答
0

我不确定这是否可行,但您可以尝试...根据您的代码,首先将 pkcs11 提供程序加载到 Security。

public void loadPkcs11(){
    String pkcs11config = "name = SmartCard\n"  + "library = c:/windows/system32/aetpkss1.dll";
    byte[] pkcs11configBytes = pkcs11config.getBytes();
    ByteArrayInputStream configStream = new ByteArrayInputStream(pkcs11configBytes);
    Provider pkcs11Provider = new sun.security.pkcs11.SunPKCS11(configStream);
    Security.addProvider(pkcs11Provider);
}

然后在您签署 SOAP 调用 loadPkcs11 方法之前,以便在您签署肥皂时该提供程序可用:

public Document signSOAPMessage(SOAPMessage soapEnvelope)
    throws SOAPException, TransformerException, WSSecurityException {

    loadPkcs11();

    Source src = soapEnvelope.getSOAPPart().getContent();
    TransformerFactory transformerFactory = TransformerFactory.newInstance();
    Transformer transformer = transformerFactory.newTransformer();
    ...

还有你的 sender.properties 文件:

org.apache.ws.security.crypto.provider=org.apache.ws.security.components.crypto.Merlin
org.apache.ws.security.crypto.merlin.keystore.type=PKCS11
# provider name, all pkcs11 provider name is "SunPKCS11-" + the value of parameter name in your configuration
org.apache.ws.security.crypto.merlin.keystore.provider=SunPKCS11-SmartCard
# smartcard pin
org.apache.ws.security.crypto.merlin.keystore.password=1111
org.apache.ws.security.crypto.merlin.keystore.alias=
#this param is not required in pkcs11
org.apache.ws.security.crypto.merlin.keystore.file=

希望这可以帮助,

于 2014-02-28T13:47:59.697 回答
0

对于这种情况,WSS4J 中有一个“MerlinDevice”加密实现。因此,只需在您的加密属性文件中定义以下内容:

org.apache.ws.security.crypto.provider=org.apache.ws.security.components.crypto.MerlinDevice
于 2014-06-16T15:25:18.577 回答