File: src\runtime\src\libraries\Common\src\System\Security\Cryptography\Pkcs\Pkcs12SafeBag.cs
Web Access
Project: src\runtime\src\libraries\System.Security.Cryptography.Pkcs\src\System.Security.Cryptography.Pkcs.csproj (System.Security.Cryptography.Pkcs)
// 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.Diagnostics;
using System.Formats.Asn1;
using System.Security.Cryptography.Asn1;
using Internal.Cryptography;

namespace System.Security.Cryptography.Pkcs
{
#if BUILDING_PKCS
    public
#else
    #pragma warning disable CA1510, CA1512
    internal
#endif
    abstract class Pkcs12SafeBag
    {
        private readonly string _bagIdValue;
        private Oid? _bagOid;
        private CryptographicAttributeObjectCollection? _attributes;

        public ReadOnlyMemory<byte> EncodedBagValue { get; }

        public CryptographicAttributeObjectCollection Attributes
        {
            get
            {
                _attributes ??= new CryptographicAttributeObjectCollection();

                return _attributes;
            }

            internal set
            {
                Debug.Assert(value != null);
                _attributes = value;
            }
        }

        protected Pkcs12SafeBag(string bagIdValue, ReadOnlyMemory<byte> encodedBagValue, bool skipCopy = false)
        {
            if (string.IsNullOrEmpty(bagIdValue))
                throw new ArgumentNullException(nameof(bagIdValue));

            // Read to ensure that there is precisely one legally encoded value.
            PkcsHelpers.EnsureSingleBerValue(encodedBagValue.Span);

            _bagIdValue = bagIdValue;
            EncodedBagValue = skipCopy ? encodedBagValue : encodedBagValue.ToArray();
        }

        public byte[] Encode()
        {
            AsnWriter writer = EncodeToNewWriter();
            return writer.Encode();
        }

        public Oid GetBagId()
        {
            _bagOid ??= new Oid(_bagIdValue);

            return _bagOid.CopyOid();
        }

        public bool TryEncode(Span<byte> destination, out int bytesWritten)
        {
            AsnWriter writer = EncodeToNewWriter();
            return writer.TryEncode(destination, out bytesWritten);
        }

        internal void EncodeTo(AsnWriter writer)
        {
            writer.PushSequence();

            writer.WriteObjectIdentifierForCrypto(_bagIdValue);

            Asn1Tag contextSpecific0 = new Asn1Tag(TagClass.ContextSpecific, 0);
            writer.PushSequence(contextSpecific0);
            writer.WriteEncodedValueForCrypto(EncodedBagValue.Span);
            writer.PopSequence(contextSpecific0);

            if (_attributes?.Count > 0)
            {
                List<AttributeAsn> attrs = PkcsHelpers.BuildAttributes(_attributes);

                writer.PushSetOf();

                foreach (AttributeAsn attr in attrs)
                {
                    attr.Encode(writer);
                }

                writer.PopSetOf();
            }

            writer.PopSequence();
        }

        private AsnWriter EncodeToNewWriter()
        {
            AsnWriter writer = new AsnWriter(AsnEncodingRules.BER);
            EncodeTo(writer);
            return writer;
        }

        internal sealed class UnknownBag : Pkcs12SafeBag
        {
            internal UnknownBag(string oidValue, ReadOnlyMemory<byte> bagValue)
                : base(oidValue, bagValue)
            {
            }
        }
    }
}