{"action":"created","issue":{"url":"https://api.github.com/repos/OPCFoundation/UA-Java/issues/145","repository_url":"https://api.github.com/repos/OPCFoundation/UA-Java","labels_url":"https://api.github.com/repos/OPCFoundation/UA-Java/issues/145/labels{/name}","comments_url":"https://api.github.com/repos/OPCFoundation/UA-Java/issues/145/comments","events_url":"https://api.github.com/repos/OPCFoundation/UA-Java/issues/145/events","html_url":"https://github.com/OPCFoundation/UA-Java/issues/145","id":325809327,"number":145,"title":"Problem in certificate thumbprint calcualtion","user":{"login":"d-rothe","id":39566710,"avatar_url":"https://avatars3.githubusercontent.com/u/39566710?v=4","gravatar_id":"","url":"https://api.github.com/users/d-rothe","html_url":"https://github.com/d-rothe","followers_url":"https://api.github.com/users/d-rothe/followers","following_url":"https://api.github.com/users/d-rothe/following{/other_user}","gists_url":"https://api.github.com/users/d-rothe/gists{/gist_id}","starred_url":"https://api.github.com/users/d-rothe/starred{/owner}{/repo}","subscriptions_url":"https://api.github.com/users/d-rothe/subscriptions","organizations_url":"https://api.github.com/users/d-rothe/orgs","repos_url":"https://api.github.com/users/d-rothe/repos","events_url":"https://api.github.com/users/d-rothe/events{/privacy}","received_events_url":"https://api.github.com/users/d-rothe/received_events","type":"User","site_admin":false},"labels":[],"state":"open","locked":false,"assignee":null,"assignees":[],"milestone":null,"comments":0,"created_at":"2018-05-23T17:47:24Z","updated_at":"2018-05-24T09:39:56Z","closed_at":null,"author_association":"NONE","body":"Hi,\r\nI found a problem in the Java stack which prevents secured communication between a java-based client and a c++-based server (in my case). The problem appears only when certificate chains are used, like in the case of CA-signed certificates obtained from a GDS.\r\n\r\nMy java test client uses the OPC Foundation Java Stack version 1.3.343. My reference server creates an application certificate with sha256RSA signature. \tIf I use the Java test client to connect to my reference server which has a self-signed certificate, establishing an encrypted connection works. However, after I use the OPC Foundation GDS to exchange the server certificate by one signed by a CA, connecting no longer works. \r\n\t\r\nWhen the clients sends the OpenSecureChannel request (Frame 139 in wireshark file connect-certfailure3.pcapng), the server responds with Bad_CertificateInvalid.  This error is shown in the client, as \r\n\r\n\t  org.opcfoundation.ua.common.ServiceResultException: Bad_CertificateInvalid (0x80120000) \"The certificate provided as a parameter is not valid.\"\r\nThe reason for the failure is also found in the wireshark log: Frame 139 OpenSecureChannel Message (client to server):\r\n\t\t ReceiverCertificateThumbprint: af00aa9711c28ee2ba053bdffa45dcc74cb6240a (hex)\r\n\tHowever, the correct thumbprint of the server certificate is (in my case) ‎74 64 eb 0b cc 76 96 14 6e 87 0f d2 2f 57 3b 78 7c c7 4a 34 (hex).\r\n\r\nThis thumbprint is not saved inside the certificate. Instead, it is calculated by the certificate viewing tool. I find that this thumbprint is shown by the Windows certificate info tool as well as by openssl, using the command \r\n\t\r\n\topenssl x509 -inform der -in <cert> -fingerprint\r\n\t\r\nSo the thumbprint calculated by the UA C++ SDK (which is set up to use openssl) seems to be correct, and the thumbprint calculated by the OPC Foundation Java Stack is wrong in this case, and that the UA SDK needs to deny the connection since it receives an incorrect thumbprint from the java client.\r\n\t\r\nThe Java Stack implements the relevant thumbprint handling in the class org.opcfoundation.ua.transport.security.Cert. The thumbprint is calculated as SHA-1 hash in the function \r\n\r\norg.opcfoundation.ua.utils.CertificateUtils.createThumbprint(byte[])\r\n\r\nand is stored in the field Cert.encodedCertificateThumbprint.\r\n\t\r\nIn my case, using Eclipse debugger on the test client, I find that  \r\n\t  byte[] serverencodedCertificateThumbprint = \r\n         [-81, 0, -86, -105, 17, -62, -114, -30, -70, 5, 59, -33, -6, 69, -36, -57, 76, -74, 36, 10] (dec)\r\n\t  =  [ af, 00, aa, 97,   11,  c2,   8e,  e2,  ba, 05,3b,  df, fa, 45,  dc,  c7, 4c,  b6, 24, 0a ] (hex)\r\n\r\nBy debugging the OPC Foundation Java Stack, I found  following problem. The thumbprint is sometimes incorrectly calculated as SHA-1 hash over the certificate chain instead of just the certificate - see commented code below, which fixes the issue.\r\n\t  \r\n\tpublic Cert(byte[] data) \r\n\tthrows ServiceResultException\r\n\t{\r\n\t\ttry {\r\n\t\t\tencodedCertificate = data;\r\n\t\t\tcertificate = CertificateUtils.decodeX509Certificate(data);\r\n\t\t\t// original code. The problem here is that data may be a certificate chain instead of a certificate.\r\n\t\t\t// Then, thumb print is incorrectly calculated as SHA-1 over chain.  \r\n\t\t\t// encodedCertificateThumbprint = CertificateUtils.createThumbprint(encodedCertificate);\r\n\t\t\t// my version\r\n\t\t\tencodedCertificateThumbprint = createThumbprint();\r\n\t\t} catch (CertificateNotYetValidException ce) {\r\n\t\t\tthrow new ServiceResultException(StatusCodes.Bad_CertificateTimeInvalid, ce);\r\n\t\t} catch (CertificateExpiredException ce) {\r\n\t\t\tthrow new ServiceResultException(StatusCodes.Bad_CertificateTimeInvalid, ce);\r\n\t\t} catch (CertificateParsingException ce) {\r\n\t\t\tthrow new ServiceResultException(StatusCodes.Bad_CertificateInvalid, ce);\r\n\t\t} catch (CertificateException ce) {\r\n\t\t\tthrow new ServiceResultException(StatusCodes.Bad_CertificateInvalid, ce);\r\n\t\t}\r\n\t}\r\n\t\r\n\tpublic Cert(X509Certificate certificate) throws CertificateEncodingException\r\n\t{\r\n\t\tencodedCertificate = certificate.getEncoded();\r\n\t\tthis.certificate = certificate;\r\n\t\t// original code. here, it should be ok.\r\n\t\t// encodedCertificateThumbprint = CertificateUtils.createThumbprint(encodedCertificate);\r\n\t\t// my version\r\n\t\tencodedCertificateThumbprint = createThumbprint();\r\n\t}\r\n\t\r\n    private byte[] createThumbprint() throws CertificateEncodingException\r\n\t{\r\n\t\tbyte[] data;\r\n\t\tdata = getCertificate().getEncoded(); // this is only a single certificate, even if constructor input was a chain.\r\n\t\ttry {\r\n\t\t\tMessageDigest shadigest = MessageDigest.getInstance(\"SHA1\");\r\n\t\t\treturn shadigest.digest(data);\r\n\t\t} catch (NoSuchAlgorithmException e) {\r\n\t\t\tthrow new Error(e);\r\n\t\t}\r\n\t}\r\n\t \r\n[connect-certfailure3b.zip](https://github.com/OPCFoundation/UA-Java/files/2032204/connect-certfailure3b.zip)\r\n"},"comment":{"url":"https://api.github.com/repos/OPCFoundation/UA-Java/issues/comments/391653451","html_url":"https://github.com/OPCFoundation/UA-Java/issues/145#issuecomment-391653451","issue_url":"https://api.github.com/repos/OPCFoundation/UA-Java/issues/145","id":391653451,"user":{"login":"bjakke","id":16825097,"avatar_url":"https://avatars2.githubusercontent.com/u/16825097?v=4","gravatar_id":"","url":"https://api.github.com/users/bjakke","html_url":"https://github.com/bjakke","followers_url":"https://api.github.com/users/bjakke/followers","following_url":"https://api.github.com/users/bjakke/following{/other_user}","gists_url":"https://api.github.com/users/bjakke/gists{/gist_id}","starred_url":"https://api.github.com/users/bjakke/starred{/owner}{/repo}","subscriptions_url":"https://api.github.com/users/bjakke/subscriptions","organizations_url":"https://api.github.com/users/bjakke/orgs","repos_url":"https://api.github.com/users/bjakke/repos","events_url":"https://api.github.com/users/bjakke/events{/privacy}","received_events_url":"https://api.github.com/users/bjakke/received_events","type":"User","site_admin":false},"created_at":"2018-05-24T09:39:55Z","updated_at":"2018-05-24T09:39:55Z","author_association":"CONTRIBUTOR","body":"Hi,\r\n\r\nThanks for the issue and suggested fixes. In practice this is more of a missing feature than maybe a direct bug, as receiving certificate chains to my knowledge is not supported at all at the moment. Also at least personally I have not been aware of any server that would actually try to send one (they would send the last of the chain and clients are expected to have all middle->root steps).\r\n\r\nEven the option to actually receive more than a single certificate is quite hidden in the spec, as most req/res and data structures only mention \"ApplicationInstanceCertificate\", which is a single ByteString of the certificate, without any references to chains. I remember reading somewhere that it should be possible to append the chain within the ByteString, but I'm currently unable to find the exact spec location where this is mentioned. \r\n\r\nSo there are 2 issues:\r\n1. Calculating the thumbprint correctly \r\n2. Actually parsing all the certs in the chain and using them for validation (currently all the chain certs must already be available from CertificateStore.getTrustedCerts for the DefaultCertificateValidator)\r\n\r\n"}}
{"actor":{"display_login":"bjakke"}}