Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

java.security.InvalidKeyException: Not an EC key: RSA #259

Open
MakakWasTaken opened this issue Aug 15, 2024 · 6 comments
Open

java.security.InvalidKeyException: Not an EC key: RSA #259

MakakWasTaken opened this issue Aug 15, 2024 · 6 comments
Assignees
Labels
Profile BDEW BDEW AS4 related

Comments

@MakakWasTaken
Copy link

I have recently started receiving the following error:
java.security.InvalidKeyException: Not an EC key: RSA
I am not really sure what causes the error, but suspect some sort of CryptoFactory problem.

The error started appearing after I added a second profile. I wanted my AS4 server to be able to both receive/send ENTSOG aswell as BDEW. This started with providing some problems with the PMode, which was handled by setting a custom PModeResolver:

AS4XServletHandler handler = new AS4XServletHandler();

handler.setPModeResolver((sPModeID, sService, sAction, sInitiatorID, sResponderID, sAgreementRef, sAddress) -> {
    if (sPModeID != null) {
        if (sPModeID.equals("ENTSOG")) {
            return ENTSOGPMode.createENTSOGPMode(sInitiatorID, sResponderID, sAddress,
                    (i, j) -> sPModeID, false);
        } else if (sPModeID.equals("BDEW")) {
            return BDEWPMode.createBDEWPMode(sInitiatorID,
                    BDEWPMode.BDEW_PARTY_ID_TYPE_BDEW, sResponderID,
                    BDEWPMode.BDEW_PARTY_ID_TYPE_BDEW, sAddress,
                    (i, j) -> sPModeID,
                    false);
        }
    }
    if (sAgreementRef.contains("entsog.eu")) {
        return ENTSOGPMode.createENTSOGPMode(sInitiatorID, sResponderID, sAddress,
                (i, j) -> "ENTSOG-" + i.getID() + "-" + j.getID(), false);
    } else if (sAgreementRef.contains("bdew.de")) {

        return BDEWPMode.createBDEWPMode(sInitiatorID, BDEWPMode.BDEW_PARTY_ID_TYPE_BDEW, sResponderID,
                BDEWPMode.BDEW_PARTY_ID_TYPE_BDEW, sAddress,
                (i, j) -> "BDEW-" + i.getID() + "-" + j.getID(), false);
    }

    LOGGER.warn("Unable to determine pMode type: " + sPModeID + ", " + sService + ", " + sAction + ", "
            + sInitiatorID + ", " + sResponderID + ", " + sAgreementRef + ", " + sAddress);

    return null;
});

The error then shifted to the sending end of the application. It won't let me set outbound files now because of the beforementioned error.

If there are any guides on how to set up multiple profiles in the same servlet it would be much appreciated. I am also aware that I could create two different endpoints for the different types of profiles, but I would prefer having them as a single endpoint instead as the handling is mostly the same for the received files.

Some configuration and the full stacktrace:

pom.xml
<dependencyManagement>
  <dependencies>
    <dependency>
      <groupId>com.helger.phase4</groupId>
      <artifactId>phase4-parent-pom</artifactId>
      <version>2.8.1</version>
      <type>pom</type>
      <scope>import</scope>
    </dependency>
  </dependencies>
</dependencyManagement>
[...]
<dependency>
  <groupId>org.bouncycastle</groupId>
  <artifactId>bcjmail-jdk15to18</artifactId>
  <version>1.78</version>
</dependency>
<dependency>
  <groupId>com.helger.phase4</groupId>
  <artifactId>phase4-lib</artifactId>
</dependency>
<dependency>
  <groupId>com.helger.phase4</groupId>
  <artifactId>phase4-profile-entsog</artifactId>
</dependency>
<dependency>
  <groupId>com.helger.phase4</groupId>
  <artifactId>phase4-profile-bdew</artifactId>
</dependency>
Full stacktrace

2024-08-15T00:14:03.578160262Z 2024-08-15T00:14:03.578Z  INFO 39 --- [p-nio-80-exec-6] c.n.c.communication.AS4Helper            : ENTSOG send result: TRANSPORT_ERROR
2024-08-15T00:14:03.585792849Z com.helger.phase4.util.Phase4Exception: Wrapped Phase4Exception
2024-08-15T00:14:03.587141664Z 	at com.nomnom.communicationserver.entsog.Phase4ENTSOGSender$AbstractENTSOGUserMessageBuilder.mainSendMessage(Phase4ENTSOGSender.java:219)
2024-08-15T00:14:03.587159864Z 	at com.helger.phase4.sender.AbstractAS4MessageBuilder.sendMessage(AbstractAS4MessageBuilder.java:856)
2024-08-15T00:14:03.587164864Z 	at com.helger.phase4.sender.AbstractAS4UserMessageBuilder.sendMessageAndCheckForReceipt(AbstractAS4UserMessageBuilder.java:816)
2024-08-15T00:14:03.587168964Z 	at com.nomnom.communicationserver.communication.AS4Helper.sendMessage(AS4Helper.java:155)
2024-08-15T00:14:03.587173264Z 	at com.nomnom.communicationserver.servlet.SenderServlet.doPost(SenderServlet.java:204)
2024-08-15T00:14:03.587176864Z 	at jakarta.servlet.http.HttpServlet.service(HttpServlet.java:590)
2024-08-15T00:14:03.587180464Z 	at jakarta.servlet.http.HttpServlet.service(HttpServlet.java:658)
2024-08-15T00:14:03.587184364Z 	at org.apache.catalina.core.ApplicationFilterChain.internalDoFilter(ApplicationFilterChain.java:205)
2024-08-15T00:14:03.587188265Z 	at org.apache.catalina.core.ApplicationFilterChain.doFilter(ApplicationFilterChain.java:149)
2024-08-15T00:14:03.587191765Z 	at org.apache.tomcat.websocket.server.WsFilter.doFilter(WsFilter.java:51)
2024-08-15T00:14:03.587205665Z 	at org.apache.catalina.core.ApplicationFilterChain.internalDoFilter(ApplicationFilterChain.java:174)
2024-08-15T00:14:03.587209465Z 	at org.apache.catalina.core.ApplicationFilterChain.doFilter(ApplicationFilterChain.java:149)
2024-08-15T00:14:03.587213065Z 	at org.springframework.web.filter.RequestContextFilter.doFilterInternal(RequestContextFilter.java:100)
2024-08-15T00:14:03.587216865Z 	at org.springframework.web.filter.OncePerRequestFilter.doFilter(OncePerRequestFilter.java:116)
2024-08-15T00:14:03.587220665Z 	at org.apache.catalina.core.ApplicationFilterChain.internalDoFilter(ApplicationFilterChain.java:174)
2024-08-15T00:14:03.587224065Z 	at org.apache.catalina.core.ApplicationFilterChain.doFilter(ApplicationFilterChain.java:149)
2024-08-15T00:14:03.587227965Z 	at org.springframework.web.filter.FormContentFilter.doFilterInternal(FormContentFilter.java:93)
2024-08-15T00:14:03.587232665Z 	at org.springframework.web.filter.OncePerRequestFilter.doFilter(OncePerRequestFilter.java:116)
2024-08-15T00:14:03.587236265Z 	at org.apache.catalina.core.ApplicationFilterChain.internalDoFilter(ApplicationFilterChain.java:174)
2024-08-15T00:14:03.587240265Z 	at org.apache.catalina.core.ApplicationFilterChain.doFilter(ApplicationFilterChain.java:149)
2024-08-15T00:14:03.587244965Z 	at org.springframework.web.filter.ServerHttpObservationFilter.doFilterInternal(ServerHttpObservationFilter.java:109)
2024-08-15T00:14:03.587248565Z 	at org.springframework.web.filter.OncePerRequestFilter.doFilter(OncePerRequestFilter.java:116)
2024-08-15T00:14:03.587253465Z 	at org.apache.catalina.core.ApplicationFilterChain.internalDoFilter(ApplicationFilterChain.java:174)
2024-08-15T00:14:03.587257365Z 	at org.apache.catalina.core.ApplicationFilterChain.doFilter(ApplicationFilterChain.java:149)
2024-08-15T00:14:03.587261065Z 	at org.springframework.web.filter.CharacterEncodingFilter.doFilterInternal(CharacterEncodingFilter.java:201)
2024-08-15T00:14:03.587264565Z 	at org.springframework.web.filter.OncePerRequestFilter.doFilter(OncePerRequestFilter.java:116)
2024-08-15T00:14:03.587268565Z 	at org.apache.catalina.core.ApplicationFilterChain.internalDoFilter(ApplicationFilterChain.java:174)
2024-08-15T00:14:03.587272265Z 	at org.apache.catalina.core.ApplicationFilterChain.doFilter(ApplicationFilterChain.java:149)
2024-08-15T00:14:03.587276466Z 	at org.apache.catalina.core.StandardWrapperValve.invoke(StandardWrapperValve.java:166)
2024-08-15T00:14:03.587280066Z 	at org.apache.catalina.core.StandardContextValve.invoke(StandardContextValve.java:90)
2024-08-15T00:14:03.587283366Z 	at org.apache.catalina.authenticator.AuthenticatorBase.invoke(AuthenticatorBase.java:482)
2024-08-15T00:14:03.587286766Z 	at org.apache.catalina.core.StandardHostValve.invoke(StandardHostValve.java:115)
2024-08-15T00:14:03.587290466Z 	at org.apache.catalina.valves.ErrorReportValve.invoke(ErrorReportValve.java:93)
2024-08-15T00:14:03.587294566Z 	at org.apache.catalina.core.StandardEngineValve.invoke(StandardEngineValve.java:74)
2024-08-15T00:14:03.587302766Z 	at org.apache.catalina.valves.RemoteIpValve.invoke(RemoteIpValve.java:738)
2024-08-15T00:14:03.587306866Z 	at org.apache.catalina.connector.CoyoteAdapter.service(CoyoteAdapter.java:341)
2024-08-15T00:14:03.587310766Z 	at org.apache.coyote.http11.Http11Processor.service(Http11Processor.java:391)
2024-08-15T00:14:03.587314466Z 	at org.apache.coyote.AbstractProcessorLight.process(AbstractProcessorLight.java:63)
2024-08-15T00:14:03.587318266Z 	at org.apache.coyote.AbstractProtocol$ConnectionHandler.process(AbstractProtocol.java:894)
2024-08-15T00:14:03.587322266Z 	at org.apache.tomcat.util.net.NioEndpoint$SocketProcessor.doRun(NioEndpoint.java:1740)
2024-08-15T00:14:03.587326466Z 	at org.apache.tomcat.util.net.SocketProcessorBase.run(SocketProcessorBase.java:52)
2024-08-15T00:14:03.587330266Z 	at org.apache.tomcat.util.threads.ThreadPoolExecutor.runWorker(ThreadPoolExecutor.java:1191)
2024-08-15T00:14:03.587334966Z 	at org.apache.tomcat.util.threads.ThreadPoolExecutor$Worker.run(ThreadPoolExecutor.java:659)
2024-08-15T00:14:03.587338966Z 	at org.apache.tomcat.util.threads.TaskThread$WrappingRunnable.run(TaskThread.java:61)
2024-08-15T00:14:03.587342766Z 	at java.base/java.lang.Thread.run(Thread.java:840)
2024-08-15T00:14:03.587346566Z Caused by: org.apache.wss4j.common.ext.WSSecurityException: java.security.InvalidKeyException: Not an EC key: RSA
2024-08-15T00:14:03.587350466Z Original Exception was javax.xml.crypto.dsig.XMLSignatureException: java.security.InvalidKeyException: Not an EC key: RSA
2024-08-15T00:14:03.587354366Z 	at org.apache.wss4j.dom.message.WSSecSignature.computeSignature(WSSecSignature.java:637)
2024-08-15T00:14:03.587358066Z 	at org.apache.wss4j.dom.message.WSSecSignature.computeSignature(WSSecSignature.java:554)
2024-08-15T00:14:03.587361666Z 	at org.apache.wss4j.dom.message.WSSecSignature.build(WSSecSignature.java:414)
2024-08-15T00:14:03.587365267Z 	at com.helger.phase4.messaging.crypto.AS4Signer._createSignedMessage(AS4Signer.java:152)
2024-08-15T00:14:03.587369367Z 	at com.helger.phase4.messaging.crypto.AS4Signer.createSignedMessage(AS4Signer.java:216)
2024-08-15T00:14:03.587373267Z 	at com.helger.phase4.client.AS4ClientUserMessage.buildMessage(AS4ClientUserMessage.java:746)
2024-08-15T00:14:03.587377167Z 	at com.helger.phase4.client.AbstractAS4Client.sendMessageWithRetries(AbstractAS4Client.java:561)
2024-08-15T00:14:03.587380967Z 	at com.helger.phase4.sender.AS4BidirectionalClientHelper.sendAS4UserMessageAndReceiveAS4SignalMessage(AS4BidirectionalClientHelper.java:138)
2024-08-15T00:14:03.587384567Z 	at com.nomnom.communicationserver.entsog.Phase4ENTSOGSender$AbstractENTSOGUserMessageBuilder.mainSendMessage(Phase4ENTSOGSender.java:199)
2024-08-15T00:14:03.587387967Z 	... 44 more
2024-08-15T00:14:03.587391667Z Caused by: javax.xml.crypto.dsig.XMLSignatureException: java.security.InvalidKeyException: Not an EC key: RSA
2024-08-15T00:14:03.587399567Z 	at org.apache.jcp.xml.dsig.internal.dom.DOMXMLSignature.sign(DOMXMLSignature.java:420)
2024-08-15T00:14:03.587403867Z 	at org.apache.wss4j.dom.message.WSSecSignature.computeSignature(WSSecSignature.java:630)
2024-08-15T00:14:03.587407367Z 	... 52 more
2024-08-15T00:14:03.587411267Z Caused by: java.security.InvalidKeyException: Not an EC key: RSA
2024-08-15T00:14:03.587414967Z 	at jdk.crypto.ec/sun.security.ec.ECKeyFactory.engineTranslateKey(ECKeyFactory.java:139)
2024-08-15T00:14:03.587418867Z 	at java.base/java.security.KeyFactory.translateKey(KeyFactory.java:469)
2024-08-15T00:14:03.587422767Z 	at jdk.crypto.ec/sun.security.ec.ECKeyFactory.toECKey(ECKeyFactory.java:99)
2024-08-15T00:14:03.587426767Z 	at jdk.crypto.ec/sun.security.ec.ECDSASignature.engineInitSign(ECDSASignature.java:372)
2024-08-15T00:14:03.587430267Z 	at jdk.crypto.ec/sun.security.ec.ECDSASignature.engineInitSign(ECDSASignature.java:365)
2024-08-15T00:14:03.587434567Z 	at java.base/java.security.Signature$Delegate.tryOperation(Signature.java:1327)
2024-08-15T00:14:03.587438067Z 	at java.base/java.security.Signature$Delegate.chooseProvider(Signature.java:1276)
2024-08-15T00:14:03.587441667Z 	at java.base/java.security.Signature$Delegate.engineInitSign(Signature.java:1373)
2024-08-15T00:14:03.587445167Z 	at java.base/java.security.Signature.initSign(Signature.java:635)
2024-08-15T00:14:03.587448967Z 	at org.apache.jcp.xml.dsig.internal.dom.DOMSignatureMethod.sign(DOMSignatureMethod.java:339)
2024-08-15T00:14:03.587452868Z 	at org.apache.jcp.xml.dsig.internal.dom.DOMXMLSignature.sign(DOMXMLSignature.java:417)
2024-08-15T00:14:03.587456568Z 	... 53 more
2024-08-15T00:14:03.587472168Z 2024-08-15T00:14:03.586Z ERROR 39 --- [p-nio-80-exec-6] c.n.c.servlet.SenderServlet              : Wrapped Phase4Exception

@phax phax self-assigned this Aug 15, 2024
@phax phax added the Profile BDEW BDEW AS4 related label Aug 15, 2024
@phax
Copy link
Owner

phax commented Aug 15, 2024

@MakakWasTaken please be aware, that BDEW does NOT work out of the box, because the key exchange stuff is not available in the underlying WSS4J library. Please see the respective entry in the discussion area. Also please bare in mind, that BDEW wants Elliptic Curve (EC) based certificates instead of RSA ones. So this will be more than just adding some PModes....

@MakakWasTaken
Copy link
Author

I am guessing that you're referring to #105. I am however a bit unsure on where to start with the implementation. I am guessing that I need some sort of PMode aware crypto factory to customize the handling of the encrypt/sign based on the PMode resolver.

So if the PMode ID starts with BDEW it would handle it with the EC based certificates. And likewise if it starts with ENTSOG I would just continue to handle it in the same way as before.

that BDEW does NOT work out of the box, because the key exchange stuff is not available in the underlying WSS4J library.

I read the discussion that you referred to, I however understood #105 (comment) as if the problem had been resolved and it was now implemented (from 2.7.5 and onwards). Is there anything else that I need to implement in order to start receiving with the BDEW profile.

Another thing is that when I started implementing the new BDEW profile, it caused the existing sending of ENTSOG to start failing. The following code is what is used for sending the message that seems to cause an error.

Phase4ENTSOGSender.ENTSOGPayloadParams entsogParams = new Phase4ENTSOGSender.ENTSOGPayloadParams();
eResult = Phase4ENTSOGSender.builder()
        // Certificate
        .cryptoFactory(CryptoHelper.cryptoFactory)
        .receiverCertificate(certificate)

        // Setup
        .endpointURL(endpointURL)
        .action("http://docs.oasis-open.org/ebxml-msg/as4/200902/action")
        .service(serviceType, service)
        .agreementRef(agreement)
        .httpRetrySettings(new HttpRetrySettings().setMaxRetries(0))

        // From Partner
        .fromRole(senderRole)
        .fromPartyID(senderId)
        .fromPartyIDType("http://www.entsoe.eu/eic-codes/eic-party-codes-x")

        // To Partner
        .toRole(receiverRole)
        .toPartyID(receiverId)
        .toPartyIDType("http://www.entsoe.eu/eic-codes/eic-party-codes-x")

        .pmodeID(as4Type)

        // Payload
        .payload(aPayloadElement, entsogParams)
        .signalMsgConsumer(signalConsumer)

        .setSigningKeyIdentifierType(ECryptoKeyIdentifierType.BST_DIRECT_REFERENCE)
        .encryptionKeyIdentifierType(ECryptoKeyIdentifierType.BST_DIRECT_REFERENCE)

        // Send the message
        .sendMessageAndCheckForReceipt(responseMessage::set);

Running this code gives me the InvalidKeyException. Which I thought was only needed when handling the BDEW profile. Is there some extra that I need to do in my CryptoFactory to account for this. If there are questions to any of the variables please feel free to ask 😄

Thanks in advance :D

@MakakWasTaken
Copy link
Author

MakakWasTaken commented Aug 16, 2024

I figured part of the problem out. I noticated that a default profile was being selected (bdew). Which caused the validation to fail. I temporarily fixed the problem by using the MetaAS4Manager.getProfileMgr().setDefaultProfileID method to set the profile id to the selected profile type right before sending. I was however wondering if there was a better solution to this? I tried using the incomingProfileSelector on Phase4ENTSOGSender, but without success.

An example of how to properly do this would be much appreciated.

EDIT: I just found this #244 (comment) 😄

Is it possible to change the receiving profile dynamically or is this done automatically?

@phax
Copy link
Owner

phax commented Aug 19, 2024

As handling multiple AS4 profiles becomes more and more of an issue, I started assembling a Wiki page that should deal with that topic: https://github.com/phax/phase4/wiki/Multi-Profile-Handling - that page is not yet finalized but it should provide a good starting point

One of the points mentioned there is also the AS4 profile ID for sending. This has indeed been resolved by #244 and will be part of the upcoming 2.8.2 release.

An indeed the implementation of https://issues.apache.org/jira/browse/SANTUARIO-511 in the 3.x branch of Apache Santuario opened up for an easier key exchange, but you need to implement it yourself. It's not "hidden" in the phase4 code atm.

hth

@MakakWasTaken
Copy link
Author

I have finally had the time to sit down and have a look at this again. I have since last posting converted to version 3.0.0. I have also generated some certificates using openssl to get the EC certificates that I needed in order to prevent this error.

openssl commands used for certificate
# Create Key
openssl ecparam -name brainpoolP256r1 -genkey -out ecdsa_private_key.pem -param_enc named_curve
# Create Certificate from key
openssl req -new -x509 -key ecdsa_private_key.pem -out ecdsa_public_key.cer -days 99999
# Create .p12 keystore using the private key and public key.
openssl pkcs12 -export -out keystore.p12 -inkey ecdsa_private_key.pem -in ecdsa_public_key.cer

I am attempting to send a BDEW message but have now ended up with the message:
java.security.SignatureException: Curve not supported: org.bouncycastle.jce.spec.ECNamedCurveSpec
I have tried looking around, both in phase4 but also just in general. And as I understand it there is a problem with the brainpoolP256r1 curve not being properly supported.

When I was looking up ECNamedCurveSpec I found the BrainpoolFuncTest and SecP256R1FuncTest test cases within the phase4-bdew-client. These seem to be running fine in my implementation with the certificates generated with the above commands. I have also tried listing the supported curves using ECNamedCurveTable.getNames() and it seems that brainpoolP256r1 is indeed included in the list.

This has now left me without any idea of how to continue. The way that I set up the BouncyCastleProvider is using the following script to do the initialization:

import org.apache.xml.security.Init;
import org.apache.xml.security.algorithms.JCEMapper;
import org.bouncycastle.jce.provider.BouncyCastleProvider;
import org.bouncycastle.jsse.provider.BouncyCastleJsseProvider;

import java.security.Security;

public class GeneralConfig {
    static {
        // Initialize the XML Security library
        Init.init();

        // Register Bouncy Castle as a security provider
        Security.addProvider(new BouncyCastleProvider());
        Security.addProvider(new BouncyCastleJsseProvider());

        // Set Bouncy Castle as the provider for specific algorithms
        JCEMapper.setProviderId(BouncyCastleProvider.PROVIDER_NAME);
    }
}

The keystore I use is using PKCS12 and I start it using m_aKeyStore = EKeyStoreType.PKCS12.getKeyStore("BC"); in my crypto factory.

I have also tried looking in the #105 discussion, but it seems that the discussion has moved to a Slack channel which I am not apart of. In case there is some relevant information in the Slack, could you invite me? ([email protected])

I apologize if I have missed something obvious. Neither Java or Cryptography are my strong suite, but I am trying to learn as I go along :) If more information is needed do not hesitate to ask. If there are some good resources for learning more about the AS4 in general I would also happily accept any suggestions.

@phax
Copy link
Owner

phax commented Dec 6, 2024

In the meantime we moved on bilaterally and are waiting for feedback. An updated will be provided as soon as it is available

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Labels
Profile BDEW BDEW AS4 related
Projects
None yet
Development

No branches or pull requests

2 participants