Uploaded image for project: 'OpenAM'
  1. OpenAM
  2. OPENAM-12801

OAuth2 token signing forces PKCS#11 keys to have specific attributes

    Details

    • Type: Bug
    • Status: Resolved
    • Priority: Major
    • Resolution: Fixed
    • Affects Version/s: 5.5.1, 6.0.0, 6.0.0.1, 6.0.0.2
    • Fix Version/s: 6.5.0
    • Component/s: oauth2, OpenID Connect
    • Labels:
    • Target Version/s:
    • Support Ticket IDs:
    • Needs QA verification:
      No

      Description

      Bug description

      To get an ID token, AM unnecessarily forces PKCS11 keys to have certain CKA_ attributes.

      How to reproduce the issue

      Configure AM 5.5 to use PKCS#11 (or SoftHSM, NSS, for example).
      https://backstage.forgerock.com/knowledge/kb/article/a56661000

      Example SoftHSM configuration:

      name = softHSM
      library = /home/fr/SoftHSMv2-develop/src/lib/.libs/libsofthsm2.so
      slot = 1167202963
      attributes(generate, *, *) =
      {
        CKA_TOKEN = true
      }
      attributes(generate, CKO_CERTIFICATE, *) =
      {
        CKA_PRIVATE = false
      }
      attributes(generate, CKO_PUBLIC_KEY, *) = {
        CKA_PRIVATE = false
      }
      

      Configure OAuth2/OIDC and request an ID token to be signed by an RSA key on the HSM.

      Expected behaviour

      Get back a ID token signed by the HSM protected key.

      Current behaviour
      `{"error_description":"Signing algorithm is 'RS256' but the private key found is not an RSA private key","error":"invalid_request"}`
      
      OAuth2Provider:03/29/2018 04:29:49:747 PM GMT: Thread[http-nio-8080-exec-9,5,main]: TransactionId[53714560-ddd0-4a3f-9533-29338f0a741f-10852] ERROR: Unhandled exception: 
      Internal Server Error (500) - The server encountered an unexpected condition which prevented it from fulfilling the request 
      at org.restlet.resource.ServerResource.doHandle(ServerResource.java:539) 
      at org.restlet.resource.ServerResource.post(ServerResource.java:1377) 
      at org.restlet.resource.ServerResource.doHandle(ServerResource.java:620) 
      at org.restlet.resource.ServerResource.doNegotiatedHandle(ServerResource.java:678) 
      at org.restlet.resource.ServerResource.doConditionalHandle(ServerResource.java:356) 
      at org.restlet.resource.ServerResource.handle(ServerResource.java:1043) 
      ... 
      
      Caused by: org.forgerock.oauth2.restlet.OAuth2RestletException: Signing algorithm is 'RS256' but the private key found is not an RSA private key 
      at org.forgerock.oauth2.restlet.TokenEndpointResource.token(TokenEndpointResource.java:94) 
      at sun.reflect.NativeMethodAccessorImpl.invoke0(Native Method) 
      at sun.reflect.NativeMethodAccessorImpl.invoke(NativeMethodAccessorImpl.java:62) 
      at sun.reflect.DelegatingMethodAccessorImpl.invoke(DelegatingMethodAccessorImpl.java:43) 
      at java.lang.reflect.Method.invoke(Method.java:498) 
      at org.restlet.resource.ServerResource.doHandle(ServerResource.java:520) 
      ... 79 more
      

      Work around

      Make sure the key is generated with:
      CKA_SENSITIVE=false
      and
      CKA_EXTRACTABLE=true

      Code analysis

      The Java PKCS11 library returns a P11PrivateKey if CKA_SENSITIVE is true or CKA_EXTRACTABLE is false. Otherwise it may return a P11RSAPrivateKey.

      In the case of P11PrivateKey, AM will not match the instance type.

      org.forgerock.openam.oauth2.jwt.JwtSigningHandler.java
          private SigningHandler getAsymmetricSigningHandler(PrivateKey privateKey) {
              switch (jwtSigningOptions.getAlgorithm().getAlgorithmType()) {
              case RSA:
                  if (!(privateKey instanceof RSAPrivateKey)) {
                      throw new IllegalArgumentException("Signing algorithm is '" + jwtSigningOptions.getAlgorithm()
                              + "' but the private key found is not an RSA private key");
                  }
                  return new SigningManager().newRsaSigningHandler(privateKey);
              case ECDSA:
                  if (!(privateKey instanceof ECPrivateKey)) {
                      throw new IllegalArgumentException("Signing algorithm is '" + jwtSigningOptions.getAlgorithm()
                              + "' but the private key found is not an EC private key");
                  }
                  return new SigningManager().newEcdsaSigningHandler((ECPrivateKey) privateKey);
              default:
                  throw new IllegalStateException("Algorithm type '" + jwtSigningOptions.getAlgorithm().getAlgorithmType()
                          + "' not supported");
              }
          }
      

      To check the instance type is a private key, if required, it may be better to do:

      privateKey instanceof PrivateKey

      To check algorithm, better to do:

      privateKey.getAlgorithm()

      and look for "RSA" or "EC".

        Attachments

          Issue Links

            Activity

              People

              • Assignee:
                Unassigned
                Reporter:
                andrew.dunn Andrew Dunn [X] (Inactive)
              • Votes:
                0 Vote for this issue
                Watchers:
                9 Start watching this issue

                Dates

                • Created:
                  Updated:
                  Resolved: