Getting started with signatures

The system offers modules to work with some cryptographic service providers (CSPs) that allow you to sign user data. The default providers include CryptoPro and NCA. Client scripts help you sign data using other cloud CSPs. To work with these features, you need to configure a digital signature in an app.

Internal signature

To get specific data and manage changes in the system, you can sign data using an internal signature. A signature of this type is not legally valid; it is used specifically to control changes in an app and capture a version of data stored in an app item. Along with the signature, you can obtain data calculated based on an app’s signature settings. With an internal signature, you can sign attributes of an item of any app type or a file in a Document type app. To get an internal signature, you need to store the app in the context or find it using the Global or Namespace objects:

async function workWithDataSigns(): Promise<void> {
    // Getting the app from the context
    // `document` is a Document type app
    const app = Context.data.document!;

    // Getting the app’s data
    const appData = await app.fetch();

    // Getting signatures
    const innerSigns = await appData.getDataSigns();

    // Getting the attributes’ internal signature to sign the data using a CSP
    const attributesInnerSign = innerSigns.find(innerSign => innerSign.type === SignType.Attributes);
    if (!attributesInnerSign) {
        throw new Error('Internal signature not found');
    }
}

Upload an obtained signature to the system

In the previous example, we signed an app item’s attributes. Each internal digital signature stores the data’s hash (data footprint) and the signed data itself. This data can then be used to send it to the CSP that signs it:

async function saveSign(): Promise<void> {
    // `SignProvider` is an example of a CSP
    // Includes one method of calculating a signature using the data
    const signProvider = new SignProvider();
    
    // Getting a signature for an app item’s attributes
    const signData = signProvider.sign(attributesInnerSign.body);
    
    const newSign: NewSign = {
        // Signature in the base64 format
        sign: signData;
        // Type of signature, depending on what needs to be signed, `signature` or `files`
        signType: attributesInnerSign.type;
        // Code of the signature provider
        codeProvider: 'signProvider';
        // ID of the base64 file
        body: attributesInnerSign.body,
        // Hash of the signed data (it is needed to identify the version of the signed data)
        hash: attributesInnerSign.hash,
    }
     
    await appData.uploadSign(newSign);
}

Get the signed attributes and the signature as a file

To get the content of the signed attributes and the signature itself, you the createAttributesFile and EntitySign.createSignFile methods. To get EntitySign, you need the history of app item signatures. To find the necessary version of the signature in the history, use the app’s internal signature:

async function getSignsFiles(): Promise<void> {
    // Getting a Document type app from the context of the client script
    const app = Context.data.document!;
    // Getting the app’s data
    const appData = await app.fetch();
    // Getting the history of an app item’s signatures
    const signsHistory = await appData.getSignHistory();
    // Getting internal signatures
    const innerSigns = await appData.getDataSigns();

    // Let’s add the attributes’ internal signature to sign the data using a CSP
    const attributesInnerSign = innerSigns.find(innerSign => innerSign.type === SignType.Attributes);
    if (!attributesInnerSign) {
        throw new Error('Internal signature not found');
    }

    // Let’s find the signatures of the last version of an app item in the signatures archive
    const signs = signsHistory.find(signs => signs.hash === attributesInnerSigns.hash);
    if (!signs) {
        throw new Error('This version is not signed');
    }

    const dataSign = signs.signs[0];

    const attributesFile = await dataSign.createAttributesFile();
    const signFile = await dataSign.createSignFile();
}

Get detailed information about a signature

The system allows you to get detailed information about a signature, including:

  • Information about the signature itself
  • Signature content
  • Information on the public key that was used to sign the data
  • Signed data

To get the information, call the EntitySign.getDetails method. This method allows you to get detailed information about a signature. Let’s say we need to define whether data was signed by an individual or a legal entity. To do that, we need to get the signature from the history and call the EntitySign.getDetails method. After obtaining the data, we need to analyze the content of the certificate:

async function whoMadeSign(): Promise<void> {
    // Getting a Document type app from the context of a client script
    const app = Context.data.document!;
    // Getting the app’s data
    const appData = await app.fetch();
    // Getting the history of an app’s signatures
    const signsHistory = await appData.getSignHistory();
    // Getting the most recent signature
    const sign = signsHistory[0].signs[0];
    // Getting information about the signature
    const signDetails = await sign.getDetails();
    
    // If one of the following fields is filled out, the data is signed by a legal entity
    // Other fields of a certificate can also be used for checks of this type,
    // depending on the provider who issued the digital signature
    const orgField = signDetails.subject['O'] || signDetails.subject['OU'];
    
    if (orgField !== '') {
        // Signed by a legal entity
    } else {
        // Signed by an individual
    }
    
}

You can also obtain information about signature certificates, including data about the issuing CA, the entity to whom the certificate was issued, and its validity period.

Here’s an example script to retrieve information about signature certificates expiring within a month:

async function signWithSoonExpiredCerts (): Promise<void> {
    // Get current user
    const user = await System.users.getCurrentUser();
    // Date the signature certificate expires
    const expiredDate = new Datetime().addDate(0, 1, 0);
    // Get the user’s signatures
    const digitalSigns = await System.signs.digitalSigns.search().where(sign => sign.__createdBy.eq(user)).all();
    // Get signatures with certificates expiring within the next month
    const expiredSigns = digitalSigns.filter(sign => sign.data.validUntilAt?.beforeOrEqual(expiredDate));

    // Write information about signatures with expiring certificates to the context
    Context.data.expiredcerts = 'Certificates expiring within a month: ';
    for (let sign of expiredSigns) {
        const subjectName = sign.data.subject ? sign.data.subject['CN'] ?? 'name unknown' : 'signer unknown';
        Context.data.expiredcerts += `${sign.id} : ${subjectName},`;
    }

    return;
}