[Date Prev][Date Next]
Re: PGP Backend design/implementation
I have just seen your mail and would like to ask you, what international
standars document you have used to implement such a schema for storing PGP
related data. I have not seen such a document, but I know, that people
related to the IETF OpenPGP group are PLANNING to develop such a draft in
the near future.
As such, the solution presented here obviously is a highly proprietary
one. However, I would suggest, that OpenLDAP should stick to international
standards as far as possible, in order to not progress implementations,
which are not agreed to, internationally, or would conflict with such
On Sun, 10 Jan 1999, Alex Iliynsky wrote:
> Date: Sun, 10 Jan 1999 20:11:18 +0300
> From: Alex Iliynsky <email@example.com>
> To: openldap-devel@OpenLDAP.org
> Subject: PGP Backend design/implementation
> Hi there!
> I just want to describe my implementation of PGP backend as requested by
> Kurt Zeilenga.
> First of all - pgp backend was designed with one main target - accept and
> process calls from PGP GUI by PGP Inc. All information about those calls was
> obtained by reverse engineering of PGP 5.5.x freeware source code and
> digging in ldap://certserver.pgp.com . All PGP-related procedures in pgp
> backend was written using PGP SDK from PGP Inc.
> PGP backend was designed to store PGP keys generated by any software, that
> compatible with PGP SDK 1.1.1.
> Currently pgp backend works fine with PGP but not limited to this task
> only. Pgp backend supports all of LDAP calls to it's database.
> Incoming PGP key stored in two entries: PGPcertificate - that contain PGP
> key itself as PGPKEY attribute, and PGPUserID that contain all valuable
> information about PGP key for fast, indexed search. PGPUserID is a children
> of PGPCertificate. ie:
> Incoming key of "Alex Iliynsky <firstname.lastname@example.org> with "long" KeyID
> "A5FF344FA9AF6B3F" will be stored in directory as:
> 1st entry:
> PGPKey:: ....
> objectclass: pgpcertificate
> 2nd entry:
> PGPUserID=Alex Iliynsky <email@example.com>,
> pgpuserid: ...
> objectclass: pgpuserid
> where BASEKEYSPACEDN is DN where all keys are stored.
> PGPUserID may have a following attributes:
> pgpuserid - userid of key owner
> pgprevoked - revokation status of key
> pgpdisabled - disabled on server if == 1
> pgpkeytype - type of key - DSS/DH or RSA
> pgpkeyid - "short" key id
> pgpsignerid - "long" key id
> pgpkeysize - size of key in bits
> pgpsubkeyid - keyid of subkey
> pgpsignerid - "long" key id of signer's key
> pgpcreatetime - key creation time in format YYYYMMDDHHmmssZ
> pgpexpiretime - key expiration date (if not exist - key will never expired)
> Several words about pgpdisabled attribute. It's not a actual key attribute
> like all others. This attribute is used for disabling key on server. All
> search calls from PGP GUI comes with filter (&(userfilter)(pgpdisabled=0)),
> except when user looking for disabled keys on server.
> There is another special entry in database. It can be only one per server
> and contain a two important attrbutes. This entry is ServerInfo
> dn: cn=pgpserverinfo
> basekeyspacedn: ou=active, o=pgp keyspace, c=US
> basependingdn: ou=pending, o=pgp keyspace, c=US
> objectclass: serverinfo
> Where - basekeyspacedn is a pointer to place in directory where all new keys
> will be stored, and basependingdn is a pointer to where temporary denied
> keys are stored. To be exact - I don't know real means of basependingdn :)
> It's not used in my version of PGP sdk/GUI. But as I understand - pendingDN
> can be used for storing keys, that failed for some reasons such as required
> authorization. PGP GUI (pgpkey) have a "partial" implementation of such
> behavior, but does not support it.
> Calls from PGP to PGP Keyserver:
> PGP issues two type of requests to Keyserver: add and search.
> Search is usual ldap search request except for one thing: PGP Key is stored
> in PGPCertificate entry, but all searches proceeds on PGPUserID entries. PGP
> doesn't interested in PGPkey details - it asks always for PGPKey attribute
> that is absent in PGPUserID entry. Because of this, pgp backend's search
> procedure checks before sending entry to client - is client requested pgpkey
> attribute? If so, it returns _parent_ entry of founded entry.
> Before any operation with server, pgpkeys sends a search request for
> ServerInfo object and extracts from it baskeyspace/basependingdn that are
> used in all following calls to server.
> Add request - is a main interface between pgp client and server.
> All Add requests from PGP client comes with dn: "pgpcertid=virtual".
> There are two significant attributes of incoming entries:
> PGPKey - contain ASCII armored PGP key for storing on server, and
> PGPRequest - contain PGP-signed request to server.
> It can be only one attribute per incoming entry - PGPkey or PGPRequest.
> PGPRequest may contain one of 3 possible requests: delete, disable and add.
> The add request is implemented in pgpkeys, but never used for unknown reason
> (may be a simple bug in parsing errors from ldap_add).
> Format of PGPRequest (after PGPDecode call):
> Request: delete[disable|add] Location: active[pending]
> [long keyid]
> [long keyid]
> [long keyid]
> [long keyid]
> On PGPRequest, server must find requested key(s) and do one of : delete this
> key from server, set pgpdisabled to 1 in this key, or add this key to server
> (unimplemented in pgpkey but possible)
> If some error is occured, server must respond with error string like " Error
> in : [long keyid] [long eyid] ..... It;s required, but not used in pgpkeys.
> PGPKey entry must be simply placed in directory as new key.
> pgp backend implemented over SLAPD LDBM backend. It own a 5 standard backend
> All other functions from ldbm backend.
> pgp_back_search is slightly modified ldbm_back_search (to return parent of
> founded entry, if pgpkey attribute us requested)
> Example of databse definition in slapd.conf (non standard definitions only)
> # new database type - pgpdb
> database pgpdb
> #indexed attributes
> index pgpuserid eq,sub
> index pgpkeyid eq
> index pgpkeysize eq
> index pgpcertid eq
> index pgpkeytype eq
> index pgpkeycreatetime eq
> index pgpkeyexpiretime eq
> index pgpdisabled eq
> index pgprevoked eq
> #basekeyspacedn and pasependingdn definition (can be obtained from server)
> basedn "OU=ACTIVE,O=PGP KEYSPACE,C=RU"
> pendingdn "OU=PENDING,O=PGP KEYSPACE,C=RU"
> # "long" keyid of Administrator's - user's that can issue Delete/Disable
> requests to server
> admincertid A5FF344FA9AF6B3F
> admincertid 0000000000000002
> admincertid 0000000000000003
> # last line in database definition - invokes initialization of all pgp
> backend's internals
> # [temporary]
> Most important modifications in core modules (slapd)
> 1. Added new pointer in Backend structure : be_pgp that holds all internals
> of pgp backend
> 2. Added a piece of code to send_ldap_result (file result.c) procedure, to
> suppress return of LDAP operation result to client in some cases (see below)
> How it works:
> pgp_back_init/config - reads and initialize all vars during server init.
> When pgp_back_add receive a request it:
> checks request for dn == "pgpcertid=virtual"
> => not equal - pass this request to ldbm_back_add
> => equal - check for presence of attributes PGPKey or PGPRequest
> => not found - exit
> => found - call corresponding Process for entry
> PGPKey Processing:
> import incoming PGPKey to KeySet
> Create PGPCertificate entry
> Create PGPUserID entry
> Check for presence PGPCertificate in database
> => not present - add PGPCertificate and PGPUserID to database using
> => present - Decide what to do with new key
> => key already exist on server - return LDAP_ALREADY_EXISTS to
> => replace old key with new one
> Create LDAPMod for changed attributes
> Call ldbm_back_modify with this MOD to PGPUserIDEntry
> Create LDAPMod for PGPKey
> Call ldbm_back_modify PGPCertificate
> Check is pgpuserid changed ?
> => no - return LDAP_SUCCESS to client
> => yes - call ldap_back_modrdn PGPUserID entry
> return result to client
> PGPRequest processing:
> Decode incoming PGPRequest using Administration's keys and check for
> => Not valid - return error to client
> => Valid
> Perform operation on each key, specified in PGPRequest
> = delete - delete this key (PGPCertificate and PGPUserID) from
> server with ldbm_back_delete
> = disable - modify "pgpdisabled" attribute in specified key
> using ldbm_back_modify
> return result to client
> To suppres return errors to client during calls of ldbm_back_*, pgp backend
> uses a op_private field in Operation structure. If it is not NULL,
> send_ldap_result assigns error values ( error_num, matched, error) to
> corresponding field of structure pointed by op_private.
> pgp backend was first implemented under WindowsNT with Eudora QSLAPD server,
> and now it ported to FreeBSD 3.0 with OpenLDAP 1.1.1.
> PGP SDK is available for free from PGP corporate homepage
> http://www.pgpi.com and is free for all non-commercial projects.
> P.S. Windows NT version of pgp backend implemented as SLAPD server you can
> get on http://rednest.rosinter.ru/apps/pgpldapnt.zip
Kurt Spanier, Zentrum fuer Datenverarbeitung, +49 7071 29-70334
Universitaet Tuebingen, DE
firstname.lastname@example.org +49 7071 29-5912
Dr. Kurt Spanier, Zentrum fuer Datenverarbeitung,
Universitaet Tuebingen, Waechterstrasse 76, D-72074 Tuebingen
finger "Kurt Spanier"@x500.uni-tuebingen.de