| File: System\Security\Cryptography\X509Certificates\SubjectAlternativeNameBuilder.cs | Web Access |
| Project: src\runtime\src\libraries\System.Security.Cryptography\src\System.Security.Cryptography.csproj (System.Security.Cryptography) |
// Licensed to the .NET Foundation under one or more agreements. // The .NET Foundation licenses this file to you under the MIT license. using System.Collections.Generic; using System.Formats.Asn1; using System.Globalization; using System.Net; using System.Security.Cryptography.Asn1; using System.Text; namespace System.Security.Cryptography.X509Certificates { public sealed class SubjectAlternativeNameBuilder { private static readonly IdnMapping s_idnMapping = new IdnMapping(); // Because GeneralNames is a SEQUENCE, just make a rolling list, it doesn't need to be re-sorted. private readonly List<byte[]> _encodedNames = new List<byte[]>(); public void AddEmailAddress(string emailAddress) { if (string.IsNullOrEmpty(emailAddress)) throw new ArgumentOutOfRangeException(nameof(emailAddress), SR.Arg_EmptyOrNullString); AddGeneralName(new GeneralNameAsn { Rfc822Name = emailAddress }); } public void AddDnsName(string dnsName) { if (string.IsNullOrEmpty(dnsName)) throw new ArgumentOutOfRangeException(nameof(dnsName), SR.Arg_EmptyOrNullString); AddGeneralName(new GeneralNameAsn { DnsName = s_idnMapping.GetAscii(dnsName) }); } public void AddUri(Uri uri) { ArgumentNullException.ThrowIfNull(uri); AddGeneralName(new GeneralNameAsn { Uri = uri.AbsoluteUri.ToString() }); } public void AddIpAddress(IPAddress ipAddress) { ArgumentNullException.ThrowIfNull(ipAddress); AddGeneralName(new GeneralNameAsn { IPAddress = ipAddress.GetAddressBytes() }); } /// <summary> /// Adds a Registered ID (OID) to the Subject Alternative Name. /// </summary> /// <param name="registeredId">The registered ID OID to add, in dotted decimal notation.</param> /// <exception cref="ArgumentOutOfRangeException"> /// <paramref name="registeredId" /> is <see langword="null" /> or <see cref="string.Empty" />. /// </exception> /// <exception cref="CryptographicException"> /// <paramref name="registeredId" /> is not a valid OID. /// </exception> public void AddRegisteredId(string registeredId) { if (string.IsNullOrEmpty(registeredId)) throw new ArgumentOutOfRangeException(nameof(registeredId), SR.Arg_EmptyOrNullString); AddGeneralName(new GeneralNameAsn { RegisteredId = registeredId }); } public void AddUserPrincipalName(string upn) { if (string.IsNullOrEmpty(upn)) throw new ArgumentOutOfRangeException(nameof(upn), SR.Arg_EmptyOrNullString); AsnWriter writer = new AsnWriter(AsnEncodingRules.DER); writer.WriteCharacterString(UniversalTagNumber.UTF8String, upn); byte[] otherNameValue = writer.Encode(); OtherNameAsn otherName = new OtherNameAsn { TypeId = Oids.UserPrincipalName, Value = otherNameValue, }; AddGeneralName(new GeneralNameAsn { OtherName = otherName }); } public X509Extension Build(bool critical = false) { AsnWriter writer = new AsnWriter(AsnEncodingRules.DER); using (writer.PushSequence()) { foreach (byte[] encodedName in _encodedNames) { writer.WriteEncodedValue(encodedName); } } return writer.Encode(critical, static (critical, encoded) => { return new X509Extension(Oids.SubjectAltName, encoded, critical); }); } private void AddGeneralName(GeneralNameAsn generalName) { try { // Verify that the general name can be serialized and store it. AsnWriter writer = new AsnWriter(AsnEncodingRules.DER); generalName.Encode(writer); _encodedNames.Add(writer.Encode()); } catch (EncoderFallbackException) { throw new CryptographicException(SR.Cryptography_Invalid_IA5String); } } } }