|
27 | 27 | * http://opcfoundation.org/License/MIT/1.00/ |
28 | 28 | * ======================================================================*/ |
29 | 29 |
|
30 | | -using Org.BouncyCastle.Asn1.Pkcs; |
31 | | -using Org.BouncyCastle.Pkcs; |
32 | 30 | using System; |
| 31 | +using System.Collections.Generic; |
33 | 32 | using System.Security.Cryptography.X509Certificates; |
34 | 33 | using System.Threading.Tasks; |
35 | 34 |
|
@@ -145,24 +144,63 @@ public virtual async Task<X509Certificate2> SigningRequestAsync( |
145 | 144 | string[] domainNames, |
146 | 145 | byte[] certificateRequest) |
147 | 146 | { |
148 | | - Pkcs10CertificationRequest pkcs10CertificationRequest = new Pkcs10CertificationRequest(certificateRequest); |
149 | | - CertificationRequestInfo info = pkcs10CertificationRequest.GetCertificationRequestInfo(); |
150 | | - DateTime yesterday = DateTime.UtcNow.AddDays(-1); |
151 | | - return CertificateFactory.CreateCertificate( |
152 | | - null, |
153 | | - null, |
154 | | - null, |
155 | | - application.ApplicationUri ?? "urn:ApplicationURI", |
156 | | - application.ApplicationNames.Count > 0 ? application.ApplicationNames[0].Text : "ApplicationName", |
157 | | - info.Subject.ToString(), |
158 | | - domainNames, |
159 | | - Configuration.DefaultCertificateKeySize, |
160 | | - yesterday, |
161 | | - Configuration.DefaultCertificateLifetime, |
162 | | - Configuration.DefaultCertificateHashSize, |
163 | | - false, |
164 | | - await LoadSigningKeyAsync(Certificate, string.Empty), |
165 | | - info.SubjectPublicKeyInfo.GetEncoded()); |
| 147 | + try |
| 148 | + { |
| 149 | + var pkcs10CertificationRequest = new Org.BouncyCastle.Pkcs.Pkcs10CertificationRequest(certificateRequest); |
| 150 | + |
| 151 | + if (!pkcs10CertificationRequest.Verify()) |
| 152 | + { |
| 153 | + throw new ServiceResultException(StatusCodes.BadInvalidArgument, "CSR signature invalid."); |
| 154 | + } |
| 155 | + |
| 156 | + var info = pkcs10CertificationRequest.GetCertificationRequestInfo(); |
| 157 | + var altNameExtension = GetAltNameExtensionFromCSRInfo(info); |
| 158 | + if (altNameExtension != null) |
| 159 | + { |
| 160 | + if (altNameExtension.Uris.Count > 0) |
| 161 | + { |
| 162 | + if (!altNameExtension.Uris.Contains(application.ApplicationUri)) |
| 163 | + { |
| 164 | + throw new ServiceResultException(StatusCodes.BadCertificateUriInvalid, |
| 165 | + "CSR AltNameExtension does not match "+ application.ApplicationUri); |
| 166 | + } |
| 167 | + } |
| 168 | + |
| 169 | + if (altNameExtension.IPAddresses.Count > 0 || altNameExtension.DomainNames.Count > 0) |
| 170 | + { |
| 171 | + var domainNameList = new List<string>(); |
| 172 | + domainNameList.AddRange(altNameExtension.DomainNames); |
| 173 | + domainNameList.AddRange(altNameExtension.IPAddresses); |
| 174 | + domainNames = domainNameList.ToArray(); |
| 175 | + } |
| 176 | + } |
| 177 | + |
| 178 | + DateTime yesterday = DateTime.UtcNow.AddDays(-1); |
| 179 | + return CertificateFactory.CreateCertificate( |
| 180 | + null, |
| 181 | + null, |
| 182 | + null, |
| 183 | + application.ApplicationUri ?? "urn:ApplicationURI", |
| 184 | + application.ApplicationNames.Count > 0 ? application.ApplicationNames[0].Text : "ApplicationName", |
| 185 | + info.Subject.ToString(), |
| 186 | + domainNames, |
| 187 | + Configuration.DefaultCertificateKeySize, |
| 188 | + yesterday, |
| 189 | + Configuration.DefaultCertificateLifetime, |
| 190 | + Configuration.DefaultCertificateHashSize, |
| 191 | + false, |
| 192 | + await LoadSigningKeyAsync(Certificate, string.Empty), |
| 193 | + info.SubjectPublicKeyInfo.GetEncoded()); |
| 194 | + } |
| 195 | + catch (Exception ex) |
| 196 | + { |
| 197 | + if (ex is ServiceResultException) |
| 198 | + { |
| 199 | + throw ex as ServiceResultException; |
| 200 | + } |
| 201 | + throw new ServiceResultException(StatusCodes.BadInvalidArgument, ex.Message); |
| 202 | + } |
| 203 | + |
166 | 204 | } |
167 | 205 |
|
168 | 206 | public virtual async Task<X509Certificate2> CreateCACertificateAsync( |
@@ -248,6 +286,33 @@ private async Task UpdateAuthorityCertInTrustedList() |
248 | 286 | } |
249 | 287 | } |
250 | 288 | } |
| 289 | + |
| 290 | + private X509SubjectAltNameExtension GetAltNameExtensionFromCSRInfo(Org.BouncyCastle.Asn1.Pkcs.CertificationRequestInfo info) |
| 291 | + { |
| 292 | + try |
| 293 | + { |
| 294 | + for (int i = 0; i < info.Attributes.Count; i++) |
| 295 | + { |
| 296 | + var sequence = Org.BouncyCastle.Asn1.Asn1Sequence.GetInstance(info.Attributes[i].ToAsn1Object()); |
| 297 | + var oid = Org.BouncyCastle.Asn1.DerObjectIdentifier.GetInstance(sequence[0].ToAsn1Object()); |
| 298 | + if (oid.Equals(Org.BouncyCastle.Asn1.Pkcs.PkcsObjectIdentifiers.Pkcs9AtExtensionRequest)) |
| 299 | + { |
| 300 | + var extensionInstance = Org.BouncyCastle.Asn1.DerSet.GetInstance(sequence[1]); |
| 301 | + var extensionSequence = Org.BouncyCastle.Asn1.Asn1Sequence.GetInstance(extensionInstance[0]); |
| 302 | + var extensions = Org.BouncyCastle.Asn1.X509.X509Extensions.GetInstance(extensionSequence); |
| 303 | + Org.BouncyCastle.Asn1.X509.X509Extension extension = extensions.GetExtension(Org.BouncyCastle.Asn1.X509.X509Extensions.SubjectAlternativeName); |
| 304 | + var asnEncodedAltNameExtension = new System.Security.Cryptography.AsnEncodedData(Org.BouncyCastle.Asn1.X509.X509Extensions.SubjectAlternativeName.ToString(), extension.Value.GetOctets()); |
| 305 | + var altNameExtension = new X509SubjectAltNameExtension(asnEncodedAltNameExtension, extension.IsCritical); |
| 306 | + return altNameExtension; |
| 307 | + } |
| 308 | + } |
| 309 | + } |
| 310 | + catch |
| 311 | + { |
| 312 | + throw new ServiceResultException(StatusCodes.BadInvalidArgument, "CSR altNameExtension invalid."); |
| 313 | + } |
| 314 | + return null; |
| 315 | + } |
251 | 316 | #endregion |
252 | 317 |
|
253 | 318 | #region Protected Fields |
|
0 commit comments