OPCFoundation / UA-.NETStandard

OPC Unified Architecture .NET Standard
Other
1.96k stars 946 forks source link

OPC UA server certificate (OPC Foundation server) #2120

Closed samirhaj closed 1 year ago

samirhaj commented 1 year ago

Type of issue

Current Behavior

Hi, We are using OPC Foundation OpcUa server in our company. SInce we want to use in production with no stoppage, we would like to have server certificates to have more extended life-time than what it has now (it has only one-year validity). I have now TWO main questions:

1- Is it possible to extend the auto-generated certificate of the OPC server to longer life-time? I also have access to the .Net source code of the Opc Server if that helps to do that in the code. I found where in the Opc Server code the LifeTimeInMonths = 12 and I changed that but it didn't work because I understood that this is a dll (or NuGet) of some X509Certificate has been used inside with some parameters that cannot be changed (because it's a NuGet if I am correct here?).

2- If the option #1 is not possible, I also have made very long life-time self-signed certificate (from a third party) that can be used it in the OpcUa server. So my question is how to add the certificate to the Opc server? In other words, how I can tell the OpcUa server to use the certificate that I have generated instead of its own generated certificates?

Best regards.

Expected Behavior

No response

Steps To Reproduce

No response

Environment

- OS:
- Environment:
- Runtime:
- Nuget Version:
- Component:
- Server:
- Client:

Anything else?

No response

mrsuciu commented 1 year ago

Hi @samirhaj,

Taking as an example the ConsoleReferenceServer:

In case you choose the first option:

\Stack\Opc.Ua.Core\Security\Certificates\CertificateFactory.cs line 48contains DefaultLifeTime = 12.

You can change the value to the desired value and recompile. This will cause the autogenerated self signed certificate lifetime to change to the desired value. Be aware that in order to regenerate the self signed application certificate you need to delete the existing one. Look into %LocalApplicationData%/OPC Foundation/pki/own and delete the "certs" and "private" folders. Run the new build and you can validate the lifetime of the newly generated self signed application certificate from the %LocalApplicationData%/OPC Foundation/pki/own/certs folder.

In case you choose the second option:

Simply replace the files with the ones you received, new ".der" replaces the existing old one from %LocalApplicationData%/OPC Foundation/pki/own/certs and new ".pfx" replaces the existing old one from %LocalApplicationData%/OPC Foundation/pki/own/private folder.

Similarly for other application configurations you have to take into account the appropriate value set for the application certificate store path and operate the changes in there.

samirhaj commented 1 year ago

Hi @mrsuciu ; I see that definitely the first option is better if it works. SO I found the CertificateFactory.cs file in the source code that you were referring to and I found the defaultLifeTime = 12, I then changed that first to 120 and next time to 60 and recompiled the code. I deleted the old certificate in the pki/own folder. But both times the new certificate that was created still have the same one year validity. For example since I did it today, the new certificate is valid until April 13th, 2024. This is what I also experienced before I post this issue in here.

We are using the OPC Foundation server with this information if that helps. Copyright (c) 2005-2016 The OPC Foundation, Inc. All rights reserved. OPC Foundation MIT License 1.00

samirhaj commented 1 year ago

@mrsuciu : Have you tried to change the defaultLifeTime in your server and it worked? Cold you try this on this OPC Foundation server that we are using and see why it does not work for me?

Best regards.

mrsuciu commented 1 year ago

@samirhaj: I have mentioned point one as an example in the case of the ConsoleReferenceServer sample application from this repository which works since it refers to the CertificateFactory source code directly and since you mentioned you have access to the code (I assumed the code from this repository). If you are using a nugget release to reference the code from this repository changing the source code has no effect and you have pick the second option and replace the certificate and private key with the new ones. Unfortunately I cannot identify the server you mentioned in this repository.

samirhaj commented 1 year ago

@mrsuciu: Ok, I see. The thing is that I have made OpcUa client certificate from the Openssl certificate (which I want to use to make server certificates as well), because on the OpcUa client that I am using, also the same problem of one-year validity exists, so I made openssl certificate to have extended life-time for client as well. So now two concerns will rise; 1- if I also make the server certificate and client certificates both from the same Openssl, this will be against OPC UA spec and it's insecure, correct? If yes, can you recommend any other certificate generator other than Openssl?

2- In case if have the server certificate from third party, by placing the certificates in the pki/own "certs" and "private" folders will be sufficient? Or should I make sure the Opc Foundation server auto-generated certificates and my certificates have the same SubjectName and/or SubjectAltName, etc? In other words, will OpcUa server picks/uses the third party certificate as long as they are in the folders mentioned above?

Best regards.

mrsuciu commented 1 year ago

@samirhaj:

If the first concern is that you cannot generate both client and server certificates from OpenSSL than it is not against OPC UA spec, as a matter of fact there are vendors which use OpenSSL in their certificate generation process.

The second concern is indeed valid since the certificates should follow the specification 6.2.2 Application Instance Certificate.

Since you have access to this repository however an easy alternative is to follow the call to Opc.Ua.CertificateFactory.CreateCertificate(string subjectName)which is available also in the OPCFoundation.NetStandard.Opc.Ua.Core nuget.

You can reference in a separate utility console application of your choice as follows:

X509Certificate2 certificate = CertificateFactory.CreateCertificate(
               "CN=Quickstart Reference Server, C=US, S=Arizona, O=OPC Foundation, DC=localhost")
               .SetLifeTime(24)         // 2 years
               .SetRSAKeySize(2048)
               .CreateForRSA();

The value of the subjectNameis picked out from the following XML tag belonging to Quickstarts.ReferenceServer.Config.xml:

<SubjectName>CN=Quickstart Reference Server, C=US, S=Arizona, O=OPC Foundation, DC=localhost</SubjectName>

You will have to write out the .der and .pfx files out of the certificate but you can check how this is done in the code and adapt to your needs.

samirhaj commented 1 year ago

@mrsuciu Thanks a lot for your answer. Yes, the console application with the using the nuget packages works fine however some outstanding question, to make sure I am doing everything correct, still exist; The link you sent regarding the specifications of a certificate that should be followed, describes different parts of a certificate. But I couldn't find the answer regarding how OpcUa server detects that the certificate that I have made should be used? By putting the certificate I made inside the "certs" and "private" folder of %LocalApplicationData%/OPC Foundation/pki/own will be enough? Or placing them in the right folders + having the same SubjectName as the server auto-generated certificate? Or in addition to SubjectName some other specs (like Subject Alternative Name) also should be the same?

mrsuciu commented 1 year ago

@samirhaj:

The answer to how the certificate is detected as being the application certificate instance is the "sum" of what you've mentioned:

  1. Certificate fields have to be set up correctly as in the specification link 6.2.2 Application Instance Certificate. This also implies that the SubjectName is set as in the field description of the spec:
    The distinguished name of the application Instance.
    The Common Name attribute shall be specified and should be the productName or a suitable equivalent. 
    ...
  2. Placing the public .der and private .pki in their corresponding "certs" and "private" folders, in case of the sample application and all applications which use a directory store path.

The Opc.Ua.CertificateFactory.CreateCertificate(string subjectName) method I mentioned actually does not set up all the relevant fields of certificate (my bad - wrong copy/paste).

You have to use the other public overload:

public static ICertificateBuilder CreateCertificate(
            string applicationUri,
            string applicationName,
            string subjectName,
            IList<string> domainNames)

The match is done by comparing the values in the application instance at runtime to the ones in the certificate, therefore yes if the values match the certificate is picked up as being the correct application certificate.

In your case the value used as input for

Usage example for ConsoleReferenceServer:

            X509Certificate2 certificate = CertificateFactory.CreateCertificate(
               "urn:localhost:UA:Quickstarts:ReferenceServer",
               "Quickstart Reference Server",
               "CN=Quickstart Reference Server, C=US, S=Arizona, O=OPC Foundation, DC=localhost",
               new List<string> { Utils.GetHostName() })
               .SetLifeTime(24)
               .SetRSAKeySize(2048)
               .CreateForRSA();

The above should replace successfully the application instance certificate both for client and server applications.

samirhaj commented 1 year ago

@mrsuciu : Thanks a lot for your comprehensive answer. Yes, I picked the public overload you mentioned in the console application I made. Understood that it was a typo in your answer. But I have made the same applicationUri, applicationName, SubjectName and domainNames as it is specified in my XML configuration file. The only difference is that for domainNames I have specified more IPAddress/DnsName, however the IPAddress/DnsName that is in my XML configuration also exists in domainNames I have configured.

The .der and .pfx was generated with the lifetime I wanted. I copied them to the PC (another computer where it should be placed that have the OpcUa server running) and put the .der part in the %LocalApplicationData%/OPC Foundation/pki/own/certs and the .pfx part in the %LocalApplicationData%/OPC Foundation/pki/own/private folder. The old certificates which was generated by the Opc server indeed was deleted.

To test the new certificate, I first restarted the Opc server, then after restarting, I checked the pki/own folder to verify that server has not created its own certificates again. Then I used the UaExpert to connect to the OpcUa server. Once I do that, I get the pop-up attached. When I click "trust Server Certificate", then I see that this certificate (which is outdated) has been dropped in the directory where UaExpert certificates are located in the pki/trusted/certs folder!!! I deleted this certificate from this folder and I also checked in the Setting->Manage Certificates window in UaExpert and I did not see the outdated certificate in the Trusted/Issuers/TLS Issuers as well (as you see in the second file attached). It should be mentioned that this certificate is the old certificate that I deleted from the directory where Opc server certificate is located and replaced it with new one that I made.

So I concluded that the server has not picked up my new certificates, so I raised the question to you regarding what are the essential parts of the certificate that should be the same. From your answer, seems like I have done everything correctly when I was creating new certificate.

Do you have any idea what the problem is here? Do have an idea why I cannot get rid of the old certificate even though I deleted that from the UaExpert trusted folder and also I made sure it does not exist in the directory where the server certificate is dropped, but once I connect to Opc server with UaExpert the message popup appears again?!!

Sorry for the long story but I wanted to make sure I mention all the details.

UaExpert popup

UaExpert Manage Certificate window

mrsuciu commented 1 year ago

@samirhaj:

The behavior looks suspicious since you mention that you have restarted the the server to test the newly created certificate and it did not create a new one which implies that it has accepted it.

This depends on how the certificate is validated by your server (probably the certificate validation is old/faulty ?).

Is your target machine using another certificate store different from the one where you tested (different from a directory store) ? If so you need to copy the new certificates there. I would check if the previous old certificate which has been validated by your server at a certain time has the same multiple IPAddress/DnsName values. If the new and the old certificate attributes Subject/Subject Alternative Name values are identic check if the old certificate Public Key is signed with the same number of bits (2048) to dismiss the improbable case when the server does not support certificates signed with less bits. When using multiple IPAddress/DnsName values check that the first added value in the domainNames is the same as the one in the DC field of the subjectName, and of coarse the same as the one in the XML configuration.

samirhaj commented 1 year ago

@mrsuciu: Yes, that is correct, the server does not create a new one when application is restarted meaning as you mentioned the certificate I placed there has been accepted. I might have said a bit unclear. The target machine and the machine that I was doing the test was the same. I actually did this certificate test on the target machine. The directory is the default directory that was mentioned before.

I have checked again. Now both subjectName and SubjectAltNames of the two certificates are totally identical. The Subject, ApplicationUri and domainNames are the same for both the old certificate and my new certificate. Both certificates have PublicKey of 2048. I also checked Version, Issuer, signatureAlgorithm, signature hash Algorithm, Key Usage and Enhanced Key Usage of both certificates are also the same.

I now use only one domain name (one IP Address) for both certificates. I checked the old certificate had only one IP Address for domainName, then I added the same for the new certificate as well. But for both certificates, the DC field in SubjectName is hostname of the machine while the domainName in the Subject Alternative Name is IP address of the machine. (so DC is not the same as IP Address of domainName)

What surprises me is that this is an outdated expired certificate. So when you delete this certificate and restart the Opc server, the new certificate with new valid date should be re-generated but it does not (which should be the indication of the fact that my certificate has been accepted). However, once I connect with UaExpert to the server, the old, outdated certificate is thrown from the server!! (Or it is dropped to the "trusted" folder when I "Trust Server Certificate" in the pop-up). I cannot find any explanation for this behavior. Any other things I might have forgotten?

samirhaj commented 1 year ago

@mrsuciu : A follow up to the issue; Is there a maximum for the LifeTime that should be specified for the certificate? For example 20 years max, 30 years max or there is no limit?

mrsuciu commented 1 year ago

@samirhaj

The domain name in SubjectName and IP in Subject Alternative Name should be ok if the previous certificate has already passed the validation with the same values. As for the LifeTime the X509Certificate supports greater limits since the types can be either UTCTime or GeneralizedTime (specified in ASN.1 format), but how this is treated in the certificate validator it is implementation specific. It can be that your implementation treats it in a particular way or has a bug in that area. It would be worth trying a lower value (3-10 years) and check the server log files. If problem persists you can at least try to debug the certificate validation code on your server and try to pinpoint the issue (if any).

mrsuciu commented 1 year ago

Please reopen if necessary