Quellcodebibliothek Statistik Leitseite products/Sources/formale Sprachen/C/Firefox/security/nss/cmd/rsapoptst/   (Browser von der Mozilla Stiftung Version 136.0.1©)  Datei vom 10.2.2025 mit Größe 21 kB image not shown  

Quelle  rsapoptst.c   Sprache: C

 
/* This Source Code Form is subject to the terms of the Mozilla Public
 * License, v. 2.0. If a copy of the MPL was not distributed with this
 * file, You can obtain one at http://mozilla.org/MPL/2.0/. */


#include <stdio.h>
#include <stdlib.h>
#include "plgetopt.h"
#include "nss.h"
#include "secutil.h"
#include "pk11table.h"
#include "secmodt.h"
#include "pk11pub.h"

struct test_args {
    char *arg;
    int mask_value;
    char *description;
};

static const struct test_args test_array[] = {
    { "all", 0x1f, "run all the tests" },
    { "e_n_p", 0x01, "public exponent, modulus, prime1" },
    { "d_n_q", 0x02, "private exponent, modulus, prime2" },
    { "d_p_q", 0x04, "private exponent, prime1, prime2" },
    { "e_d_q", 0x08, "public exponent, private exponent, prime2" },
    { "e_d_n", 0x10, "public exponent, private exponent, modulus" }
};
static const int test_array_size =
    (sizeof(test_array) / sizeof(struct test_args));

static void
Usage(char *progName)
{
    int i;
#define PRINTUSAGE(subject, option, predicate) \
    fprintf(stderr, "%10s %s\t%s\n", subject, option, predicate);
    fprintf(stderr, "%s [-k keysize] [-e exp] [-r rounds] [-t tests]\n "
                    "Test creating RSA private keys from Partial components\n",
            progName);
    PRINTUSAGE("""-k""key size (in bit)");
    PRINTUSAGE("""-e""rsa public exponent");
    PRINTUSAGE("""-r""number times to repeat the test");
    PRINTUSAGE("""-t""run the specified tests");
    for (i = 0; i < test_array_size; i++) {
        PRINTUSAGE("", test_array[i].arg, test_array[i].description);
    }
    fprintf(stderr, "\n");
}

/*
 * Test the RSA populate command to see that it can really build
 * keys from it's components.
 */


const static CK_ATTRIBUTE rsaTemplate[] = {
    { CKA_CLASS, NULL, 0 },
    { CKA_KEY_TYPE, NULL, 0 },
    { CKA_TOKEN, NULL, 0 },
    { CKA_SENSITIVE, NULL, 0 },
    { CKA_PRIVATE, NULL, 0 },
    { CKA_ID, NULL, 0 },
    { CKA_MODULUS, NULL, 0 },
    { CKA_PUBLIC_EXPONENT, NULL, 0 },
    { CKA_PRIVATE_EXPONENT, NULL, 0 },
    { CKA_PRIME_1, NULL, 0 },
    { CKA_PRIME_2, NULL, 0 },
    { CKA_EXPONENT_1, NULL, 0 },
    { CKA_EXPONENT_2, NULL, 0 },
    { CKA_COEFFICIENT, NULL, 0 },
};

#define RSA_SIZE (sizeof(rsaTemplate))
#define RSA_ATTRIBUTES (sizeof(rsaTemplate) / sizeof(CK_ATTRIBUTE))

static void
resetTemplate(CK_ATTRIBUTE *attribute, int start, int end)
{
    int i;
    for (i = start; i < end; i++) {
        if (attribute[i].pValue) {
            PORT_Free(attribute[i].pValue);
        }
        attribute[i].pValue = NULL;
        attribute[i].ulValueLen = 0;
    }
}

static SECStatus
copyAttribute(PK11ObjectType objType, void *object, CK_ATTRIBUTE *template,
              int offset, CK_ATTRIBUTE_TYPE attrType)
{
    SECItem attributeItem = { 0, 0, 0 };
    SECStatus rv;

    rv = PK11_ReadRawAttribute(objType, object, attrType, &attributeItem);
    if (rv != SECSuccess) {
        return rv;
    }
    template[offset].type = attrType;
    template[offset].pValue = attributeItem.data;
    template[offset].ulValueLen = attributeItem.len;
    return SECSuccess;
}

static SECStatus
readKey(PK11ObjectType objType, void *object, CK_ATTRIBUTE *template,
        int start, int end)
{
    int i;
    SECStatus rv;

    for (i = start; i < end; i++) {
        rv = copyAttribute(objType, object, template, i, template[i].type);
        if (rv != SECSuccess) {
            goto fail;
        }
    }
    return SECSuccess;

fail:
    resetTemplate(template, start, i);
    return rv;
}

#define ATTR_STRING(x) getNameFromAttribute(x)

static void
dumphex(FILE *file, const unsigned char *cpval, int start, int end)
{
    int i;
    for (i = start; i < end; i++) {
        if ((i % 16) == 0)
            fprintf(file, "\n ");
        fprintf(file, " %02x", cpval[i]);
    }
    return;
}

void
dumpTemplate(FILE *file, const CK_ATTRIBUTE *templateint start, int end)
{
    int i;
    for (i = start; i < end; i++) {
        unsigned char cval;
        CK_ULONG ulval;
        const unsigned char *cpval;

        fprintf(file, "%s:", ATTR_STRING(template[i].type));
        switch (template[i].ulValueLen) {
            case 1:
                cval = *(unsigned char *)template[i].pValue;
                switch (cval) {
                    case 0:
                        fprintf(file, " false");
                        break;
                    case 1:
                        fprintf(file, " true");
                        break;
                    default:
                        fprintf(file, " %d (=0x%02x,'%c')", cval, cval, cval);
                        break;
                }
                break;
            case sizeof(CK_ULONG):
                ulval = *(CK_ULONG *)template[i].pValue;
                fprintf(file, " %ld (=0x%04lx)", ulval, ulval);
                break;
            default:
                cpval = (const unsigned char *)template[i].pValue;
                dumphex(file, cpval, 0, template[i].ulValueLen);
                break;
        }
        fprintf(file, "\n");
    }
}

void
dumpItem(FILE *file, const SECItem *item)
{
    const unsigned char *cpval;

    if (item == NULL) {
        fprintf(file, " pNULL ");
        return;
    }
    if (item->data == NULL) {
        fprintf(file, " NULL ");
        return;
    }
    if (item->len == 0) {
        fprintf(file, " Empty ");
        return;
    }
    cpval = item->data;
    dumphex(file, cpval, 0, item->len);
    fprintf(file, " ");
    return;
}

PRBool
rsaKeysAreEqual(PK11ObjectType srcType, void *src,
                PK11ObjectType destType, void *dest)
{

    CK_ATTRIBUTE srcTemplate[RSA_ATTRIBUTES];
    CK_ATTRIBUTE destTemplate[RSA_ATTRIBUTES];
    PRBool areEqual = PR_TRUE;
    SECStatus rv;
    int i;

    memcpy(srcTemplate, rsaTemplate, RSA_SIZE);
    memcpy(destTemplate, rsaTemplate, RSA_SIZE);

    rv = readKey(srcType, src, srcTemplate, 0, RSA_ATTRIBUTES);
    if (rv != SECSuccess) {
        printf("Could read source key\n");
        return PR_FALSE;
    }
    rv = readKey(destType, dest, destTemplate, 0, RSA_ATTRIBUTES);
    if (rv != SECSuccess) {
        printf("Could read dest key\n");
        return PR_FALSE;
    }

    for (i = 0; i < RSA_ATTRIBUTES; i++) {
        if (srcTemplate[i].type == CKA_ID) {
            continue/* we purposefully make the CKA_ID different */
        }
        if (srcTemplate[i].ulValueLen != destTemplate[i].ulValueLen) {
            printf("key->%s not equal src_len = %ld, dest_len=%ld\n",
                   ATTR_STRING(srcTemplate[i].type),
                   srcTemplate[i].ulValueLen, destTemplate[i].ulValueLen);
            areEqual = 0;
        } else if (memcmp(srcTemplate[i].pValue, destTemplate[i].pValue,
                          destTemplate[i].ulValueLen) != 0) {
            printf("key->%s not equal.\n", ATTR_STRING(srcTemplate[i].type));
            areEqual = 0;
        }
    }
    if (!areEqual) {
        fprintf(stderr, "original key:\n");
        dumpTemplate(stderr, srcTemplate, 0, RSA_ATTRIBUTES);
        fprintf(stderr, "created key:\n");
        dumpTemplate(stderr, destTemplate, 0, RSA_ATTRIBUTES);
    }
    resetTemplate(srcTemplate, 0, RSA_ATTRIBUTES);
    resetTemplate(destTemplate, 0, RSA_ATTRIBUTES);
    return areEqual;
}

static int exp_exp_prime_fail_count = 0;

#define LEAK_ID 0xf

static int
doRSAPopulateTest(unsigned int keySize, unsigned long exponent,
                  int mask, int round, void *pwarg)
{
    SECKEYPrivateKey *rsaPrivKey;
    SECKEYPublicKey *rsaPubKey;
    PK11GenericObject *tstPrivKey;
    CK_ATTRIBUTE tstTemplate[RSA_ATTRIBUTES];
    int tstHeaderCount;
    PK11SlotInfo *slot = NULL;
    PK11RSAGenParams rsaParams;
    CK_OBJECT_CLASS obj_class = CKO_PRIVATE_KEY;
    CK_KEY_TYPE key_type = CKK_RSA;
    CK_BBOOL ck_false = CK_FALSE;
    CK_BYTE cka_id[2] = { 0, 0 };
    int failed = 0;
    int leak_found;      /* did we find the expected leak */
    int expect_leak = 0; /* are we expecting a leak? */

    rsaParams.pe = exponent;
    rsaParams.keySizeInBits = keySize;

    slot = PK11_GetInternalSlot();
    if (slot == NULL) {
        fprintf(stderr, "Couldn't get the internal slot for the test \n");
        return -1;
    }

    rsaPrivKey = PK11_GenerateKeyPair(slot, CKM_RSA_PKCS_KEY_PAIR_GEN,
                                      &rsaParams, &rsaPubKey, PR_FALSE,
                                      PR_FALSE, pwarg);
    if (rsaPrivKey == NULL) {
        fprintf(stderr, "RSA Key Gen failed");
        PK11_FreeSlot(slot);
        return -1;
    }

    memcpy(tstTemplate, rsaTemplate, RSA_SIZE);

    tstTemplate[0].pValue = &obj_class;
    tstTemplate[0].ulValueLen = sizeof(obj_class);
    tstTemplate[1].pValue = &key_type;
    tstTemplate[1].ulValueLen = sizeof(key_type);
    tstTemplate[2].pValue = &ck_false;
    tstTemplate[2].ulValueLen = sizeof(ck_false);
    tstTemplate[3].pValue = &ck_false;
    tstTemplate[3].ulValueLen = sizeof(ck_false);
    tstTemplate[4].pValue = &ck_false;
    tstTemplate[4].ulValueLen = sizeof(ck_false);
    tstTemplate[5].pValue = &cka_id[0];
    tstTemplate[5].ulValueLen = sizeof(cka_id);
    tstHeaderCount = 6;
    cka_id[0] = round;

    if (mask & 1) {
        printf("%s\n", test_array[1].description);
        resetTemplate(tstTemplate, tstHeaderCount, RSA_ATTRIBUTES);
        cka_id[1] = 0;
        copyAttribute(PK11_TypePrivKey, rsaPrivKey, tstTemplate,
                      tstHeaderCount, CKA_PUBLIC_EXPONENT);
        copyAttribute(PK11_TypePrivKey, rsaPrivKey, tstTemplate,
                      tstHeaderCount + 1, CKA_MODULUS);
        copyAttribute(PK11_TypePrivKey, rsaPrivKey, tstTemplate,
                      tstHeaderCount + 2, CKA_PRIME_1);

        tstPrivKey = PK11_CreateManagedGenericObject(slot, tstTemplate,
                                                     tstHeaderCount +
                                                         3,
                                                     PR_FALSE);
        if (tstPrivKey == NULL) {
            fprintf(stderr, "RSA Populate failed: pubExp mod p\n");
            failed = 1;
        } else if (!rsaKeysAreEqual(PK11_TypePrivKey, rsaPrivKey,
                                    PK11_TypeGeneric, tstPrivKey)) {
            fprintf(stderr, "RSA Populate key mismatch: pubExp mod p\n");
            failed = 1;
        }
        if (tstPrivKey)
            PK11_DestroyGenericObject(tstPrivKey);
    }
    if (mask & 2) {
        printf("%s\n", test_array[2].description);
        /* test the basic2 case, public exponent, modulus, prime2 */
        resetTemplate(tstTemplate, tstHeaderCount, RSA_ATTRIBUTES);
        cka_id[1] = 1;
        copyAttribute(PK11_TypePrivKey, rsaPrivKey, tstTemplate,
                      tstHeaderCount, CKA_PUBLIC_EXPONENT);
        copyAttribute(PK11_TypePrivKey, rsaPrivKey, tstTemplate,
                      tstHeaderCount + 1, CKA_MODULUS);
        copyAttribute(PK11_TypePrivKey, rsaPrivKey, tstTemplate,
                      tstHeaderCount + 2, CKA_PRIME_2);
        /* test with q in the prime1 position */
        tstTemplate[tstHeaderCount + 2].type = CKA_PRIME_1;

        tstPrivKey = PK11_CreateManagedGenericObject(slot, tstTemplate,
                                                     tstHeaderCount +
                                                         3,
                                                     PR_FALSE);
        if (tstPrivKey == NULL) {
            fprintf(stderr, "RSA Populate failed: pubExp mod q\n");
            failed = 1;
        } else if (!rsaKeysAreEqual(PK11_TypePrivKey, rsaPrivKey,
                                    PK11_TypeGeneric, tstPrivKey)) {
            fprintf(stderr, "RSA Populate key mismatch: pubExp mod q\n");
            failed = 1;
        }
        if (tstPrivKey)
            PK11_DestroyGenericObject(tstPrivKey);
    }
    if (mask & 4) {
        printf("%s\n", test_array[3].description);
        /* test the medium case, private exponent, prime1, prime2 */
        resetTemplate(tstTemplate, tstHeaderCount, RSA_ATTRIBUTES);
        cka_id[1] = 2;

        copyAttribute(PK11_TypePrivKey, rsaPrivKey, tstTemplate,
                      tstHeaderCount, CKA_PRIVATE_EXPONENT);
        copyAttribute(PK11_TypePrivKey, rsaPrivKey, tstTemplate,
                      tstHeaderCount + 1, CKA_PRIME_1);
        copyAttribute(PK11_TypePrivKey, rsaPrivKey, tstTemplate,
                      tstHeaderCount + 2, CKA_PRIME_2);
        /* test with p & q swapped. Underlying code should swap these back */
        tstTemplate[tstHeaderCount + 2].type = CKA_PRIME_1;
        tstTemplate[tstHeaderCount + 1].type = CKA_PRIME_2;

        tstPrivKey = PK11_CreateManagedGenericObject(slot, tstTemplate,
                                                     tstHeaderCount +
                                                         3,
                                                     PR_FALSE);
        if (tstPrivKey == NULL) {
            fprintf(stderr, "RSA Populate failed: privExp p q\n");
            failed = 1;
        } else if (!rsaKeysAreEqual(PK11_TypePrivKey, rsaPrivKey,
                                    PK11_TypeGeneric, tstPrivKey)) {
            fprintf(stderr, "RSA Populate key mismatch: privExp p q\n");
            failed = 1;
        }
        if (tstPrivKey)
            PK11_DestroyGenericObject(tstPrivKey);
    }
    if (mask & 8) {
        printf("%s\n", test_array[4].description);
        /* test the advanced case, public exponent, private exponent, prime2 */
        resetTemplate(tstTemplate, tstHeaderCount, RSA_ATTRIBUTES);
        cka_id[1] = 3;
        copyAttribute(PK11_TypePrivKey, rsaPrivKey, tstTemplate,
                      tstHeaderCount, CKA_PRIVATE_EXPONENT);
        copyAttribute(PK11_TypePrivKey, rsaPrivKey, tstTemplate,
                      tstHeaderCount + 1, CKA_PUBLIC_EXPONENT);
        copyAttribute(PK11_TypePrivKey, rsaPrivKey, tstTemplate,
                      tstHeaderCount + 2, CKA_PRIME_2);

        tstPrivKey = PK11_CreateManagedGenericObject(slot, tstTemplate,
                                                     tstHeaderCount +
                                                         3,
                                                     PR_FALSE);
        if (tstPrivKey == NULL) {
            fprintf(stderr, "RSA Populate failed: pubExp privExp q\n");
            fprintf(stderr, " this is expected periodically. It means we\n");
            fprintf(stderr, " had more than one key that meets the "
                            "specification\n");
            exp_exp_prime_fail_count++;
        } else if (!rsaKeysAreEqual(PK11_TypePrivKey, rsaPrivKey,
                                    PK11_TypeGeneric, tstPrivKey)) {
            fprintf(stderr, "RSA Populate key mismatch: pubExp privExp q\n");
            failed = 1;
        }
        if (tstPrivKey)
            PK11_DestroyGenericObject(tstPrivKey);
    }
    if (mask & 0x10) {
        printf("%s\n", test_array[5].description);
        /* test the advanced case2, public exponent, private exponent, modulus
         */

        resetTemplate(tstTemplate, tstHeaderCount, RSA_ATTRIBUTES);
        cka_id[1] = LEAK_ID;

        copyAttribute(PK11_TypePrivKey, rsaPrivKey, tstTemplate,
                      tstHeaderCount, CKA_PRIVATE_EXPONENT);
        copyAttribute(PK11_TypePrivKey, rsaPrivKey, tstTemplate,
                      tstHeaderCount + 1, CKA_PUBLIC_EXPONENT);
        copyAttribute(PK11_TypePrivKey, rsaPrivKey, tstTemplate,
                      tstHeaderCount + 2, CKA_MODULUS);

        /* purposefully use the old version. This will create a leak */
        tstPrivKey = PK11_CreateGenericObject(slot, tstTemplate,
                                              tstHeaderCount +
                                                  3,
                                              PR_FALSE);
        if (tstPrivKey == NULL) {
            fprintf(stderr, "RSA Populate failed: pubExp privExp mod\n");
            failed = 1;
        } else if (!rsaKeysAreEqual(PK11_TypePrivKey, rsaPrivKey,
                                    PK11_TypeGeneric, tstPrivKey)) {
            fprintf(stderr, "RSA Populate key mismatch: pubExp privExp mod\n");
            failed = 1;
        }
        expect_leak = 1;
        if (tstPrivKey)
            PK11_DestroyGenericObject(tstPrivKey);
    }
    resetTemplate(tstTemplate, tstHeaderCount, RSA_ATTRIBUTES);
    SECKEY_DestroyPrivateKey(rsaPrivKey);
    SECKEY_DestroyPublicKey(rsaPubKey);

    /* make sure we didn't leak */
    leak_found = 0;
    tstPrivKey = PK11_FindGenericObjects(slot, CKO_PRIVATE_KEY);
    if (tstPrivKey) {
        SECStatus rv;
        PK11GenericObject *thisKey;
        int i;

        fprintf(stderr, "Leaking keys...\n");
        for (i = 0, thisKey = tstPrivKey; thisKey; i++,
            thisKey = PK11_GetNextGenericObject(thisKey)) {
            SECItem id = { 0, NULL, 0 };

            rv = PK11_ReadRawAttribute(PK11_TypeGeneric, thisKey,
                                       CKA_ID, &id);
            if (rv != SECSuccess) {
                fprintf(stderr, "Key %d: couldn't read CKA_ID: %s\n",
                        i, PORT_ErrorToString(PORT_GetError()));
                continue;
            }
            fprintf(stderr, "id = { ");
            dumpItem(stderr, &id);
            fprintf(stderr, "};");
            if (id.data[1] == LEAK_ID) {
                fprintf(stderr, " ---> leak expected\n");
                if (id.data[0] == round)
                    leak_found = 1;
            } else {
                if (id.len != sizeof(cka_id)) {
                    fprintf(stderr,
                            " ---> ERROR unexpected leak in generated key\n");
                } else {
                    fprintf(stderr,
                            " ---> ERROR unexpected leak in constructed key\n");
                }
                failed = 1;
            }
            SECITEM_FreeItem(&id, PR_FALSE);
        }
        PK11_DestroyGenericObjects(tstPrivKey);
    }
    if (expect_leak && !leak_found) {
        fprintf(stderr, "ERROR expected leak not found\n");
        failed = 1;
    }

    PK11_FreeSlot(slot);
    return failed ? -1 : 0;
}

/* populate options */
enum {
    opt_Exponent = 0,
    opt_KeySize,
    opt_Repeat,
    opt_Tests
};

static secuCommandFlag populate_options[] = {
    { /* opt_Exponent   */ 'e', PR_TRUE, 0, PR_FALSE },
    { /* opt_KeySize    */ 'k', PR_TRUE, 0, PR_FALSE },
    { /* opt_Repeat     */ 'r', PR_TRUE, 0, PR_FALSE },
    { /* opt_Tests      */ 't', PR_TRUE, 0, PR_FALSE },
};

int
is_delimiter(char c)
{
    if ((c == '+') || (c == ',') || (c == '|')) {
        return 1;
    }
    return 0;
}

int
parse_tests(char *test_string)
{
    int mask = 0;
    int i;

    while (*test_string) {
        if (is_delimiter(*test_string)) {
            test_string++;
        }
        for (i = 0; i < test_array_size; i++) {
            char *arg = test_array[i].arg;
            int len = strlen(arg);
            if (strncmp(test_string, arg, len) == 0) {
                test_string += len;
                mask |= test_array[i].mask_value;
                break;
            }
        }
        if (i == test_array_size) {
            break;
        }
    }
    return mask;
}

int
main(int argc, char **argv)
{
    unsigned int keySize = 1024;
    unsigned long exponent = 65537;
    int i, repeat = 1, ret = 0;
    SECStatus rv = SECFailure;
    secuCommand populateArgs;
    char *progName;
    int mask = 0xff;

    populateArgs.numCommands = 0;
    populateArgs.numOptions = sizeof(populate_options) /
                              sizeof(secuCommandFlag);
    populateArgs.commands = NULL;
    populateArgs.options = populate_options;

    progName = strrchr(argv[0], '/');
    if (!progName)
        progName = strrchr(argv[0], '\\');
    progName = progName ? progName + 1 : argv[0];

    rv = NSS_NoDB_Init(NULL);
    if (rv != SECSuccess) {
        SECU_PrintPRandOSError(progName);
        return -1;
    }

    rv = SECU_ParseCommandLine(argc, argv, progName, &populateArgs);
    if (rv == SECFailure) {
        fprintf(stderr, "%s: command line parsing error!\n", progName);
        Usage(progName);
        return -1;
    }
    rv = SECFailure;

    if (populateArgs.options[opt_KeySize].activated) {
        keySize = PORT_Atoi(populateArgs.options[opt_KeySize].arg);
    }
    if (populateArgs.options[opt_Repeat].activated) {
        repeat = PORT_Atoi(populateArgs.options[opt_Repeat].arg);
    }
    if (populateArgs.options[opt_Exponent].activated) {
        exponent = PORT_Atoi(populateArgs.options[opt_Exponent].arg);
    }
    if (populateArgs.options[opt_Tests].activated) {
        char *test_string = populateArgs.options[opt_Tests].arg;
        mask = PORT_Atoi(test_string);
        if (mask == 0) {
            mask = parse_tests(test_string);
        }
        if (mask == 0) {
            Usage(progName);
            return -1;
        }
    }

    exp_exp_prime_fail_count = 0;
    for (i = 0; i < repeat; i++) {
        printf("Running RSA Populate test run %d\n", i);
        ret = doRSAPopulateTest(keySize, exponent, mask, i, NULL);
        if (ret != 0) {
            i++;
            break;
        }
    }
    if (ret != 0) {
        fprintf(stderr, "RSA Populate test round %d: FAILED\n", i);
    }
    if (repeat > 1) {
        printf(" pub priv prime test: %d failures out of %d runs (%f %%)\n",
               exp_exp_prime_fail_count, i,
               (((double)exp_exp_prime_fail_count) * 100.0) / (double)i);
    }
    if (NSS_Shutdown() != SECSuccess) {
        fprintf(stderr, "Shutdown failed\n");
        ret = -1;
    }
    return ret;
}

Messung V0.5
C=98 H=92 G=94

¤ Dauer der Verarbeitung: 0.16 Sekunden  (vorverarbeitet)  ¤

*© Formatika GbR, Deutschland






Wurzel

Suchen

Beweissystem der NASA

Beweissystem Isabelle

NIST Cobol Testsuite

Cephes Mathematical Library

Wiener Entwicklungsmethode

Haftungshinweis

Die Informationen auf dieser Webseite wurden nach bestem Wissen sorgfältig zusammengestellt. Es wird jedoch weder Vollständigkeit, noch Richtigkeit, noch Qualität der bereit gestellten Informationen zugesichert.

Bemerkung:

Die farbliche Syntaxdarstellung und die Messung sind noch experimentell.