Web of Trust

Introduction
Methods and Settings
Sample use case
Example code

Introduction

OpenPGP Web of Trust (WoT) is a formal way to identify the validity of third party public keys based on our own assumptions or their relation to other public keys we already posses.

This chapter describes how the Web of Trust is implemented in DidiSoft OpenPGP Library for .NET version 1.7.14 and above. The WoT works only with keys located in a KeyStore.

The standard way to verify OpenPGP keys is by manually checking their fingerprint with the key owner over a secure channel (the most secure being meeting in person). The drawback of this is that it’s time consuming and unpractical when we have to deal with a lot of keys on a day to day basis. Here comes the Web of Trust which allows newly imported keys to be verified checking the relation of their signatures with the existing and verified public keys already located in our key storage.

The WoT uses two terms in order to express how trustworthy is a given key: Verified and Trust value.

Verified key

Verified is a boolean property of a key indicating are we certain that the key belongs to the person or company we expect it from. When True, we have either manually verified it or according to the Web of Trust algorithm its identity has been verified. When False, we still have no evidence that it belongs to those it claims to.

C#

// ks is of type DidiSoft.Pgp.KeyStore
bool verified = ks.IsVerified("ceo@company.com");

VB.NET

' ks is of type DidiSoft.Pgp.KeyStore
Dim verified As Boolean = ks.IsVerified("ceo@company.com")

Trust value

The Trust value is how much we trust the owner of this key to be careful and responsible when signing third party keys. It’s a value in the range 0-255, with higher values meaning more trust and zero being not trusted at all. The library works with a subset of the available Trust values, defined in the enumeration TrustLevel:

    public enum TrustLevel
    {
        /// No trust value was set. This value cannot be assigned directly.
        Unknown = 0,
        /// Not trusted 
        None = 0,
        /// Partially trusted third party keys
        Marginal = 60,
        /// Maximum trust for third party keys
        Trusted = 120,
        /// Ultimate trust, usually for our own private keys
        Ultimate = 255
    }

Trust is set manually by us or calculated by the library based on the key signatures and their relation with other keys. Keys generated within the current key store have auto set trust of value TrustLevel.Ultimate.
C# example

// ks is of type DidiSoft.Pgp.KeyStore
TrustLevel trust = ks.GetTrust("ceo@company.com");
TrustLevel ownTrust = ks.GetOwnerTrust("ceo@company.com"); // trust set explicitly by us with SetTrust

VB.NET

' ks is of type DidiSoft.Pgp.KeyStore
Dim trust As TrustLevel = ks.GetTrust("ceo@company.com")
Dim ownTrust As TrustLevel = ks.GetOwnerTrust("ceo@company.com") ' trust set explicitly by us with SetTrust

Basically a key is treated as Verified if its Trust value is equal or greater than TrustLevel.Trusted, or if it is signed by at least one key with Trust value TrustLevel.Trusted, or if it is signed by at least three (see MarginalsNeeded below) keys with Marginal trust, or it has a chain of trust signatures that can be verified at a certain depth (see MaxTrustDepth below).

Methods and Settings

The library exposes the OpenPGP Web of Trust through a set of settings and methods described below.

MarginalsNeeded: The minimum number of signatures from keys with trust value at least TrustLevel.Marginal that a given key must posses in order to be Verified. The default value is 3.

// ks is of type DidiSoft.Pgp.KeyStore
ks.MarginalsNeeded = 3;

MaxTrustDepth: The depth at which the trust chain of signatures is checked in order to calculate is a key Verified or its Trust value. The default value is 3.

// ks is of type DidiSoft.Pgp.KeyStore
ks.MaxTrustDepth = 3;

TreatPrivateKeysAsUltimatelyTrusted: Unfortunately previous versions of the library didn’t set trust for generated key pairs. If we set this property to True (the default value is False) all private keys generated with versions of the library prior 1.7.14 within the current KeyStore will be treated as ultimately trusted, just like the newly generated. A drawback of turning this property on is that someone can bypass the Web of Trust by giving us a combined public and private .pgp keys in one file and when we import them, the public key will automatically be Ultimately Trusted and Verified because we have its private key.

// ks is of type DidiSoft.Pgp.KeyStore
ks.TreatPrivateKeysAsUltimatelyTrusted = false;

SetTrust(): This method is used when we want to manually set own trust value for a key. Trust set this way has meaning only within the current key store.

C# example

// ks is of type DidiSoft.Pgp.KeyStore
ks.SetTrust("ceo@company.com", TrustLevel.Trusted);

VB.NET example

' ks is of type DidiSoft.Pgp.KeyStore
ks.SetTrust("ceo@company.com", TrustLevel.Trusted)

SignPublicKey() : Signing a key with our private key means that we verify that this key belongs to the person we expect, but doesn’t indicate how much we trust him in relation to other keys. Such key is Verified.

C# example

// ks is of type DidiSoft.Pgp.KeyStore
ks.SignPublicKey("ceo@company.com", "my key user id", "my password");

VB.NET example

' ks is of type DidiSoft.Pgp.KeyStore
ks.SignPublicKey("ceo@company.com", "my key user id", "my password")

SignPublicKeyAsTrustedIntroducer(): Signing a key this way is like a combination of SetTrust and SignPublicKey. The addition here is that we can specify how deep within the chain of Web of Trust we believe in signatures made by this key. Keys with trust signatures with depth greater than one (1) are called meta-introducers and they act on behalf of us up to MaxTrustDepth deep in key to key relations in order to calculate automatically is a key Verified or to get its Trust value.

C# example

byte depth = 3;
bool exportable = true;
// ks is of type DidiSoft.Pgp.KeyStore
ks.SignPublicKeyAsTrustedIntroducer("ceo@company.com", "my key user id", "my password", depth, exportable);

VB.NET example

Dim depth As Byte = 3
Dim exportable As Boolean = True
' ks is of type DidiSoft.Pgp.KeyStore
ks.SignPublicKeyAsTrustedIntroducer("ceo@company.com", "my key user id", "my password", depth, exportable)

Example Use Case

Web of Trust in a sample companyA picture is worth a thousand words. So let’s see an example scenario where the WoT can be utilized.

We have received keys from our co-workers and CEO, that have signature chain illustrated in the picture above. We have verified the key of the CEO and we have set it as our trusted introducer (we believe in the chief management:) up to three levels down:

byte depth = 3;
bool exportable = true;
// ks is DidiSoft.Pgp.KeyStore
ks.SignPublicKeyAsTrustedIntroducer("CEO", "my_key_id", "my password", depth, exportable);

Now the trust and verified status is as follows:

Key Verified TrustLevel
CEO Verified Trusted
Manager Verified Trusted
Staff Verified Trusted
Contractor Verified None

How is this calculated?

Signing the CEO as meta introducer three levels down is like telling – we believe him to correctly sign keys up to three levels down counted from her key as if it was our key. But the CEO key has signed the Manager with trust two levels down, which is OK , because the Contractor is two levels down counted from the Manager.

Web of Trust second exampleIn a similar scenario where the CEO has certified the Manager only one level deep we have:

Key Verified TrustLevel
CEO True Trusted
Manager True Trusted
Staff True None
Contractor False None

Here the Contractor cannot be verified because the CEO has signed the Manager with trust depth = 1, which as described above is equal to sign a key (we verify that this key belongs to the right person) and we trust his judgement when he verifies others (this is why Staff identity is verified), but the trust signatures from the Manager are not accepted for meta – introducing.

Example Code

The example KeyTool application (WinForms project) that ships with the library demonstrates key signing in the form FormSignKey:

OpenPGP key signing demo

And a key Verified status and Trust can be seen in the form FormKeyProperties

PGP Key Properies

Summary

The Web of Trust functionality was implemented in version 1.7.14 of DidiSoft OpenPGP Library for .NET. In previous versions only setting own trust was available. At its current state WoT is providing the same experience that you may observe in Symantec PGP product line. Other OpenPGP implementations may take their own abstractions over the Trust value of a key, like GnuPG which uses different naming for the key Verified status – it is named validity there and may have more than two possible values.

The Web of Trust is not a mandatory component of the OpenPGP standard, and as such it’s up to the application architect to determine how to utilize this functionality.

List of methods used

KeyStore.MarginalsNeeded Setting how many signatures from keys with Trust Marginal are needed in order a key to be Verified
KeyStore.MaxTrustDepth Setting how deep is the Web of Trust checked when traversing trust signatures
KeyStore.TreatPrivateKeysAsUltimatelyTrusted Should imported private keys be treated as ultimately trusted, just like generated ones
KeyStore.IsVerified Is a key verified
KeyStore.GetTrust Returns the key trust value (set by us and the one from the Web of Trust)
KeyStore.GetOwnerTrust Returns the key trust value set by us, without the Web of Trust
KeyStore.SetTrust Sets own trust for a key
KeyStore.SignPublicKey Signs a public key identifying it as verified by us
KeyStore.SignPublicKeyAsTrustedIntroducer Signs a public key identifying it as verified and trusted to identify third party keys on behalf of us.