Sign Up

Sign Up to our social questions and Answers Engine to ask questions, answer people’s questions, and connect with other people.

Have an account? Sign In

Have an account? Sign In Now

Sign In

Login to our social questions & Answers Engine to ask questions answer people’s questions & connect with other people.

Sign Up Here

Forgot Password?

Don't have account, Sign Up Here

Forgot Password

Lost your password? Please enter your email address. You will receive a link and will create a new password via email.

Have an account? Sign In Now

You must login to ask a question.

Forgot Password?

Need An Account, Sign Up Here

Please briefly explain why you feel this question should be reported.

Please briefly explain why you feel this answer should be reported.

Please briefly explain why you feel this user should be reported.

Sign InSign Up

The Archive Base

The Archive Base Logo The Archive Base Logo

The Archive Base Navigation

  • SEARCH
  • Home
  • About Us
  • Blog
  • Contact Us
Search
Ask A Question

Mobile menu

Close
Ask a Question
  • Home
  • Add group
  • Groups page
  • Feed
  • User Profile
  • Communities
  • Questions
    • New Questions
    • Trending Questions
    • Must read Questions
    • Hot Questions
  • Polls
  • Tags
  • Badges
  • Buy Points
  • Users
  • Help
  • Buy Theme
  • SEARCH
Home/ Questions/Q 734111
In Process

The Archive Base Latest Questions

Editorial Team
  • 0
Editorial Team
Asked: May 14, 20262026-05-14T07:20:04+00:00 2026-05-14T07:20:04+00:00

I am having a problem using the signedCMS.decode routine. See the code below. The

  • 0

I am having a problem using the signedCMS.decode routine. See the code below.

The error seems to occur when the file size is too big in this case 11MB.

private static void RemoveZfoSignature(string zfoFileName)
{
    byte[] fileContents = File.ReadAllBytes(zfoFileName);
    var contentInfo = new ContentInfo(fileContents);
    var signedCms = new SignedCms(contentInfo);

    // This line throws the error 100% of the time
    signedCms.Decode(fileContents);

    signedCms.RemoveSignature(0);
    byte[] outfile = signedCms.ContentInfo.Content;
    string outFileName = zfoFileName.Replace(".zfo", "_tmp.zfo");
    File.WriteAllBytes(outFileName, outfile);
}

Here is the exact error:

"System.Security.Cryptography.CryptographicException: ASN1 out of memory.

   at System.Security.Cryptography.Pkcs.SignedCms.OpenToDecode(Byte[] encodedMessage, ContentInfo contentInfo, Boolean detached)
   at System.Security.Cryptography.Pkcs.SignedCms.Decode(Byte[] encodedMessage)
   at ConsoleApplication2.Program.RemoveZfoSignature(String zfoFileName) in C:\\Users\\\\Documents\\Visual Studio 2008\\Projects\\ConsoleApplication2\\ConsoleApplication2\\Program.cs:line 30"

Any idea on how to fix this?

I’ve updated the code now to look like this, but now its failing on the removeSignature saying The CMS Message is not signed.

/// <summary>
/// Removes the ZFO signature from the ZFO, so that it is possible to extract attachments.
/// </summary>
/// <param name="zfoFileName">
/// The zfo file name.
/// </param>
private static void RemoveZfoSignature(string zfoFileName)
    {
        string outFileName = zfoFileName.Replace(".zfo", "_tmp.zfo"); 
        FileStream inFile = null;
        FileStream outFile = null;
        inFile = File.Open(zfoFileName, FileMode.Open);
        outFile = File.Create(outFileName);
        LargeCMS.CMS cms = new LargeCMS.CMS(); 
        cms.Decode(inFile, outFile);

        // Clean up
        if (inFile != null) { inFile.Close(); }
        if (outFile != null) { outFile.Close(); }

        byte[] fileContents = File.ReadAllBytes(outFileName);
        var contentInfo = new ContentInfo(fileContents);
        var signedCms = new SignedCms(contentInfo);
        //signedCms.Decode(fileContents);
        signedCms.RemoveSignature(0);
        byte[] outfileContent = signedCms.ContentInfo.Content;

        File.WriteAllBytes(outFileName, outfileContent);
    }
  • 1 1 Answer
  • 0 Views
  • 0 Followers
  • 0
Share
  • Facebook
  • Report

Leave an answer
Cancel reply

You must login to add an answer.

Forgot Password?

Need An Account, Sign Up Here

1 Answer

  • Voted
  • Oldest
  • Recent
  • Random
  1. Editorial Team
    Editorial Team
    2026-05-14T07:20:04+00:00Added an answer on May 14, 2026 at 7:20 am

    As per this page:

    There is a counter in the ASN structure that is increased every time an octet block is processed when the ASN sequence that wraps the octets is BER encoded. It adds the number of bytes that have already been processed plus the new block size; as the number of processed bytes grows that is added to the counter and the rate at which the counter grows increases. Since the counter is represented by an integer it can overflow. On Windows 7, the ASN code checks for overflow so the function fails. On pre-Windows 7 platforms, the overflow still occurs but it wasn’t checked. That counter is not critical for operation and did not cause issues in the code for the previous versions of the OS.

    The only resolution seems to be calling the native, lower level functions listed on that page. See here for an example.

    All the following code comes from that page (duplicated here in case that page ever goes down):

    File form1.cs:

    using System;
    using System.Collections.Generic;
    using System.ComponentModel;
    using System.Data;
    using System.Drawing;
    using System.Linq;
    using System.Text;
    using System.Windows.Forms;
    using System.Security.Cryptography.X509Certificates;
    using System.IO;
    
    namespace LargeCMS
    {
        public partial class Form1 : Form
        {
            public Form1()
            {
                InitializeComponent();
    
                subjectTextBox.Text = "ALEX";
                originalTextBox.Text = "my1GBfile.txt";
                encodedTextBox.Text = "encodeddata.p7s";
                decodedTextBox.Text = "decodeddata.txt";
            }
    
            private void encodeButton_Click(object sender, EventArgs e)
            {
                // Variables
                X509Store store = null;
                X509Certificate2 cert = null;
                FileStream inFile = null;
                FileStream outFile = null;
                CMS cms = null;
    
                try
                {
                    // Get user cert
                    store = new X509Store(StoreName.My, StoreLocation.CurrentUser);
                    store.Open(OpenFlags.MaxAllowed);
                    cert = store.Certificates.Find(X509FindType.FindBySubjectName, subjectTextBox.Text, true)[0];
    
                    // Open file with data to encode
                    inFile = File.Open(originalTextBox.Text, FileMode.Open);
    
                    // Create file for encoded data
                    outFile = File.Create(encodedTextBox.Text);
    
                    // Encode data
                    cms = new CMS();
                    cms.Encode(cert, inFile, outFile);
    
                    MessageBox.Show("Sucess!!!");
                }
                catch (Exception ex)
                {
                    // Show errors
                    if (ex.InnerException != null)
                    {
                        MessageBox.Show(ex.Message + "\n" + ex.InnerException.Message);
                    }
                    else
                    {
                        MessageBox.Show(ex.Message);
                    }
                }
                finally
                {
                    // Clean up
                    if (store != null) { store.Close(); }
                    if (inFile != null) { inFile.Close(); }
                    if (outFile != null) { outFile.Close(); }
                }
            }
    
            private void decodeButton_Click(object sender, EventArgs e)
            {
                // Variables
                FileStream inFile = null;
                FileStream outFile = null;
                CMS cms = null;
    
                try
                {
                    // Open file with data to decode
                    inFile = File.Open(encodedTextBox.Text, FileMode.Open);
    
                    // Create file for encoded data
                    outFile = File.Create(decodedTextBox.Text);
    
                    // Decode data
                    cms = new CMS();
                    cms.Decode(inFile, outFile);
    
                    MessageBox.Show("Sucess!!!");
                }
                catch (Exception ex)
                {
                    if (ex.InnerException != null)
                    {
                        MessageBox.Show(ex.Message + "\n" + ex.InnerException.Message);
                    }
                    else
                    {
                        MessageBox.Show(ex.Message);
                    }
                }
                finally
                {
                    // Clean up
                    if (inFile != null) { inFile.Close(); }
                    if (outFile != null) { outFile.Close(); }
                }
    
            }
        }
    }
    

    File cms.cs:

    using System;
    using System.Collections.Generic;
    using System.Linq;
    using System.Text;
    using System.IO;
    using System.Security.Cryptography;
    using System.Security.Cryptography.X509Certificates;
    using System.Runtime.InteropServices;
    using System.ComponentModel;
    
    namespace LargeCMS
    {
        class CMS
        {
            // File stream to use in callback function
            private FileStream m_callbackFile;
    
            // Streaming callback function for encoding
            private Boolean StreamOutputCallback(IntPtr pvArg, IntPtr pbData, int cbData, Boolean fFinal)
            {
                // Write all bytes to encoded file
                Byte[] bytes = new Byte[cbData];
                Marshal.Copy(pbData, bytes, 0, cbData);
                m_callbackFile.Write(bytes, 0, cbData);
    
                if (fFinal)
                {
                    // This is the last piece. Close the file
                    m_callbackFile.Flush();
                    m_callbackFile.Close();
                    m_callbackFile = null;
                }
    
                return true;
            }
    
            // Encode CMS with streaming to support large data
            public void Encode(X509Certificate2 cert, FileStream inFile, FileStream outFile)
            {
                // Variables
                Win32.CMSG_SIGNER_ENCODE_INFO SignerInfo;
                Win32.CMSG_SIGNED_ENCODE_INFO SignedInfo;
                Win32.CMSG_STREAM_INFO StreamInfo;
                Win32.CERT_CONTEXT[] CertContexts = null;
                Win32.BLOB[] CertBlobs;
    
                X509Chain chain = null;
                X509ChainElement[] chainElements = null;
                X509Certificate2[] certs = null;
                RSACryptoServiceProvider key = null;
                BinaryReader stream = null;
                GCHandle gchandle = new GCHandle();
    
                IntPtr hProv = IntPtr.Zero;
                IntPtr SignerInfoPtr = IntPtr.Zero;
                IntPtr CertBlobsPtr = IntPtr.Zero;
                IntPtr hMsg = IntPtr.Zero;
                IntPtr pbPtr = IntPtr.Zero;
                Byte[] pbData;
                int dwFileSize;
                int dwRemaining;
                int dwSize;
                Boolean bResult = false;
    
                try
                {
                    // Get data to encode
                    dwFileSize = (int)inFile.Length;
                    stream = new BinaryReader(inFile);
                    pbData = stream.ReadBytes(dwFileSize);
    
                    // Prepare stream for encoded info
                    m_callbackFile = outFile;
    
                    // Get cert chain
                    chain = new X509Chain();
                    chain.Build(cert);
                    chainElements = new X509ChainElement[chain.ChainElements.Count];
                    chain.ChainElements.CopyTo(chainElements, 0);
    
                    // Get certs in chain
                    certs = new X509Certificate2[chainElements.Length];
                    for (int i = 0; i < chainElements.Length; i++)
                    {
                        certs[i] = chainElements[i].Certificate;
                    }
    
                    // Get context of all certs in chain
                    CertContexts = new Win32.CERT_CONTEXT[certs.Length];
                    for (int i = 0; i < certs.Length; i++)
                    {
                        CertContexts[i] = (Win32.CERT_CONTEXT)Marshal.PtrToStructure(certs[i].Handle, typeof(Win32.CERT_CONTEXT));
                    }
    
                    // Get cert blob of all certs
                    CertBlobs = new Win32.BLOB[CertContexts.Length];
                    for (int i = 0; i < CertContexts.Length; i++)
                    {
                        CertBlobs[i].cbData = CertContexts[i].cbCertEncoded;
                        CertBlobs[i].pbData = CertContexts[i].pbCertEncoded;
                    }
    
                    // Get CSP of client certificate
                    key = (RSACryptoServiceProvider)certs[0].PrivateKey;
    
                    bResult = Win32.CryptAcquireContext(
                        ref hProv,
                        key.CspKeyContainerInfo.KeyContainerName,
                        key.CspKeyContainerInfo.ProviderName,
                        key.CspKeyContainerInfo.ProviderType,
                        0
                    );
                    if (!bResult)
                    {
                        throw new Exception("CryptAcquireContext error #" + Marshal.GetLastWin32Error().ToString(), new Win32Exception(Marshal.GetLastWin32Error()));
                    }
    
                    // Populate Signer Info struct
                    SignerInfo = new Win32.CMSG_SIGNER_ENCODE_INFO();
                    SignerInfo.cbSize = Marshal.SizeOf(SignerInfo);
                    SignerInfo.pCertInfo = CertContexts[0].pCertInfo;
                    SignerInfo.hCryptProvOrhNCryptKey = hProv;
                    SignerInfo.dwKeySpec = (int)key.CspKeyContainerInfo.KeyNumber;
                    SignerInfo.HashAlgorithm.pszObjId = Win32.szOID_OIWSEC_sha1;
    
                    // Populate Signed Info struct
                    SignedInfo = new Win32.CMSG_SIGNED_ENCODE_INFO();
                    SignedInfo.cbSize = Marshal.SizeOf(SignedInfo);
    
                    SignedInfo.cSigners = 1;
                    SignerInfoPtr = Marshal.AllocHGlobal(Marshal.SizeOf(SignerInfo));
                    Marshal.StructureToPtr(SignerInfo, SignerInfoPtr, false);
                    SignedInfo.rgSigners = SignerInfoPtr;
    
                    SignedInfo.cCertEncoded = CertBlobs.Length;
                    CertBlobsPtr = Marshal.AllocHGlobal(Marshal.SizeOf(CertBlobs[0]) * CertBlobs.Length);
                    for (int i = 0; i < CertBlobs.Length; i++)
                    {
                        Marshal.StructureToPtr(CertBlobs[i], new IntPtr(CertBlobsPtr.ToInt64() + (Marshal.SizeOf(CertBlobs[i]) * i)), false);
                    }               
                    SignedInfo.rgCertEncoded = CertBlobsPtr;
    
                    // Populate Stream Info struct
                    StreamInfo = new Win32.CMSG_STREAM_INFO();
                    StreamInfo.cbContent = dwFileSize;
                    StreamInfo.pfnStreamOutput = new Win32.StreamOutputCallbackDelegate(StreamOutputCallback);
    
                    // TODO: CMSG_DETACHED_FLAG
    
                    // Open message to encode
                    hMsg = Win32.CryptMsgOpenToEncode(
                        Win32.X509_ASN_ENCODING | Win32.PKCS_7_ASN_ENCODING,
                        0,
                        Win32.CMSG_SIGNED,
                        ref SignedInfo,
                        null,
                        ref StreamInfo
                    );
                    if (hMsg.Equals(IntPtr.Zero))
                    {
                        throw new Exception("CryptMsgOpenToEncode error #" + Marshal.GetLastWin32Error().ToString(), new Win32Exception(Marshal.GetLastWin32Error()));
                    }
    
                    // Process the whole message
                    gchandle = GCHandle.Alloc(pbData, GCHandleType.Pinned);
                    pbPtr = gchandle.AddrOfPinnedObject();
                    dwRemaining = dwFileSize;
                    dwSize = (dwFileSize < 1024 * 1000 * 100) ? dwFileSize : 1024 * 1000 * 100;
                    while (dwRemaining > 0)
                    {
                        // Update message piece by piece     
                        bResult = Win32.CryptMsgUpdate(
                            hMsg,
                            pbPtr,
                            dwSize,
                            (dwRemaining <= dwSize) ? true : false
                        );
                        if (!bResult)
                        {
                            throw new Exception("CryptMsgUpdate error #" + Marshal.GetLastWin32Error().ToString(), new Win32Exception(Marshal.GetLastWin32Error()));
                        }
    
                        // Move to the next piece
                        pbPtr = new IntPtr(pbPtr.ToInt64() + dwSize);
                        dwRemaining -= dwSize;
                        if (dwRemaining < dwSize)
                        {
                            dwSize = dwRemaining;
                        }
                    }
                }
                finally
                {
                    // Clean up
                    if (gchandle.IsAllocated)
                    {
                        gchandle.Free();
                    }
                    if (stream != null)
                    {
                        stream.Close();
                    }
                    if (m_callbackFile != null)
                    {
                        m_callbackFile.Close();
                    }
                    if (!CertBlobsPtr.Equals(IntPtr.Zero))
                    {
                        Marshal.FreeHGlobal(CertBlobsPtr);
                    }
    
                    if (!SignerInfoPtr.Equals(IntPtr.Zero))
                    {
                        Marshal.FreeHGlobal(SignerInfoPtr);
                    }
                    if (!hProv.Equals(IntPtr.Zero))
                    {
                        Win32.CryptReleaseContext(hProv, 0);
                    }
                    if (!hMsg.Equals(IntPtr.Zero))
                    {
                        Win32.CryptMsgClose(hMsg);
                    }
                }
            }
    
            // Decode CMS with streaming to support large data
            public void Decode(FileStream inFile, FileStream outFile)
            {
                // Variables
                Win32.CMSG_STREAM_INFO StreamInfo;
                Win32.CERT_CONTEXT SignerCertContext;
    
                BinaryReader stream = null;
                GCHandle gchandle = new GCHandle();
    
                IntPtr hMsg = IntPtr.Zero;
                IntPtr pSignerCertInfo = IntPtr.Zero;
                IntPtr pSignerCertContext = IntPtr.Zero;
                IntPtr pbPtr = IntPtr.Zero;
                IntPtr hStore = IntPtr.Zero;
                Byte[] pbData;
                Boolean bResult = false;
                int dwFileSize;
                int dwRemaining;
                int dwSize;
                int cbSignerCertInfo;
    
                try
                {
                    // Get data to decode
                    dwFileSize = (int)inFile.Length;
                    stream = new BinaryReader(inFile);
                    pbData = stream.ReadBytes(dwFileSize);
    
                    // Prepare stream for decoded info
                    m_callbackFile = outFile;
    
                    // Populate Stream Info struct
                    StreamInfo = new Win32.CMSG_STREAM_INFO();
                    StreamInfo.cbContent = dwFileSize;
                    StreamInfo.pfnStreamOutput = new Win32.StreamOutputCallbackDelegate(StreamOutputCallback);
    
                    // Open message to decode
                    hMsg = Win32.CryptMsgOpenToDecode(
                        Win32.X509_ASN_ENCODING | Win32.PKCS_7_ASN_ENCODING,
                        0,
                        0,
                        IntPtr.Zero,
                        IntPtr.Zero,
                        ref StreamInfo
                    );
                    if (hMsg.Equals(IntPtr.Zero))
                    {
                        throw new Exception("CryptMsgOpenToDecode error #" + Marshal.GetLastWin32Error().ToString(), new Win32Exception(Marshal.GetLastWin32Error()));
                    }
    
                    // Process the whole message
                    gchandle = GCHandle.Alloc(pbData, GCHandleType.Pinned);
                    pbPtr = gchandle.AddrOfPinnedObject();
                    dwRemaining = dwFileSize;
                    dwSize = (dwFileSize < 1024 * 1000 * 100) ?  dwFileSize : 1024 * 1000 * 100;
                    while (dwRemaining > 0)
                    {
                        // Update message piece by piece     
                        bResult = Win32.CryptMsgUpdate(
                            hMsg,
                            pbPtr,
                            dwSize,
                            (dwRemaining <= dwSize) ? true : false
                        );
                        if (!bResult)
                        {
                            throw new Exception("CryptMsgUpdate error #" + Marshal.GetLastWin32Error().ToString(), new Win32Exception(Marshal.GetLastWin32Error()));
                        }
    
                        // Move to the next piece
                        pbPtr = new IntPtr(pbPtr.ToInt64() + dwSize);
                        dwRemaining -= dwSize;
                        if (dwRemaining < dwSize)
                        {
                            dwSize = dwRemaining;
                        }
                    }
    
                    // Get signer certificate info
                    cbSignerCertInfo = 0;
                    bResult = Win32.CryptMsgGetParam(
                        hMsg,
                        Win32.CMSG_SIGNER_CERT_INFO_PARAM,
                        0,
                        IntPtr.Zero,
                        ref cbSignerCertInfo
                    );
                    if (!bResult)
                    {
                        throw new Exception("CryptMsgGetParam error #" + Marshal.GetLastWin32Error().ToString(), new Win32Exception(Marshal.GetLastWin32Error()));
                    }
    
                    pSignerCertInfo = Marshal.AllocHGlobal(cbSignerCertInfo);
    
                    bResult = Win32.CryptMsgGetParam(
                        hMsg,
                        Win32.CMSG_SIGNER_CERT_INFO_PARAM,
                        0,
                        pSignerCertInfo,
                        ref cbSignerCertInfo
                    );
                    if (!bResult)
                    {
                        throw new Exception("CryptMsgGetParam error #" + Marshal.GetLastWin32Error().ToString(), new Win32Exception(Marshal.GetLastWin32Error()));
                    }
    
                    // Open a cert store in memory with the certs from the message
                    hStore = Win32.CertOpenStore(
                        Win32.CERT_STORE_PROV_MSG,
                        Win32.X509_ASN_ENCODING | Win32.PKCS_7_ASN_ENCODING,
                        IntPtr.Zero,
                        0,
                        hMsg
                    );
                    if (hStore.Equals(IntPtr.Zero))
                    {
                        throw new Exception("CertOpenStore error #" + Marshal.GetLastWin32Error().ToString(), new Win32Exception(Marshal.GetLastWin32Error()));
                    }
    
                    // Find the signer's cert in the store
                    pSignerCertContext = Win32.CertGetSubjectCertificateFromStore(
                        hStore,
                        Win32.X509_ASN_ENCODING | Win32.PKCS_7_ASN_ENCODING,
                        pSignerCertInfo
                    );
                    if (pSignerCertContext.Equals(IntPtr.Zero))
                    {
                        throw new Exception("CertGetSubjectCertificateFromStore error #" + Marshal.GetLastWin32Error().ToString(), new Win32Exception(Marshal.GetLastWin32Error()));
                    }
    
                    // Set message for verifying
                    SignerCertContext = (Win32.CERT_CONTEXT)Marshal.PtrToStructure(pSignerCertContext, typeof(Win32.CERT_CONTEXT));                
                    bResult = Win32.CryptMsgControl(
                        hMsg, 
                        0, 
                        Win32.CMSG_CTRL_VERIFY_SIGNATURE,
                        SignerCertContext.pCertInfo
                    );
                    if (!bResult)
                    {
                        throw new Exception("CryptMsgControl error #" + Marshal.GetLastWin32Error().ToString(), new Win32Exception(Marshal.GetLastWin32Error()));
                    }
                }
                finally
                {
                    // Clean up
                    if (gchandle.IsAllocated)
                    {
                        gchandle.Free();
                    }
                    if (!pSignerCertContext.Equals(IntPtr.Zero))
                    {
                        Win32.CertFreeCertificateContext(pSignerCertContext);
                    }
                    if (!pSignerCertInfo.Equals(IntPtr.Zero))
                    {
                        Marshal.FreeHGlobal(pSignerCertInfo);
                    }
                    if (!hStore.Equals(IntPtr.Zero))
                    {
                        Win32.CertCloseStore(hStore, Win32.CERT_CLOSE_STORE_FORCE_FLAG);
                    }
                    if (stream != null)
                    {
                        stream.Close();
                    }
                    if (m_callbackFile != null)
                    {
                        m_callbackFile.Close();
                    }
                    if (!hMsg.Equals(IntPtr.Zero))
                    {
                        Win32.CryptMsgClose(hMsg);
                    }
                }
            }
        }
    }
    
    • 0
    • Reply
    • Share
      Share
      • Share on Facebook
      • Share on Twitter
      • Share on LinkedIn
      • Share on WhatsApp
      • Report

Sidebar

Ask A Question

Stats

  • Questions 381k
  • Answers 381k
  • Best Answers 0
  • User 1
  • Popular
  • Answers
  • Editorial Team

    How to approach applying for a job at a company ...

    • 7 Answers
  • Editorial Team

    How to handle personal stress caused by utterly incompetent and ...

    • 5 Answers
  • Editorial Team

    What is a programmer’s life like?

    • 5 Answers
  • Editorial Team
    Editorial Team added an answer This particular case is safe, yes. Reading and writing to… May 14, 2026 at 10:08 pm
  • Editorial Team
    Editorial Team added an answer I've never run into a situation where Mysql caching was… May 14, 2026 at 10:08 pm
  • Editorial Team
    Editorial Team added an answer NSPlaceHolder is a 'singleton'* used by the foundation libraries to… May 14, 2026 at 10:08 pm

Trending Tags

analytics british company computer developers django employee employer english facebook french google interview javascript language life php programmer programs salary

Top Members

Explore

  • Home
  • Add group
  • Groups page
  • Communities
  • Questions
    • New Questions
    • Trending Questions
    • Must read Questions
    • Hot Questions
  • Polls
  • Tags
  • Badges
  • Users
  • Help
  • SEARCH

Footer

© 2021 The Archive Base. All Rights Reserved
With Love by The Archive Base

Insert/edit link

Enter the destination URL

Or link to existing content

    No search term specified. Showing recent items. Search or use up and down arrow keys to select an item.