1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
172
173
174
175
176
177
178
179
180
181
182
183
184
185
186
187
188
189
190
191
192
193
194
195
196
197
198
199
200
201
202
203
204
205
206
207
208
209
210
211
212
213
214
215
216
217
218
219
220
221
222
223
224
225
226
227
228
229
230
231
232
233
234
235
236
237
238
239
240
241
242
243
244
245
246
247
248
249
250
251
252
253
254
255
256
257
258
259
260
261
262
263
264
265
266
267
268
269
270
271
272
273
274
275
276
277
278
279
280
281
282
283
284
285
286
287
288
289
290
291
292
293
294
295
296
297
298
299
300
301
302
303
304
305
306
307
308
309
310
311
312
313
314
315
316
317
318
319
320
321
322
323
324
325
326
327
328
329
330
331
332
333
334
335
336
337
338
339
340
341
342
343
344
345
346
347
348
349
350
351
352
353
354
355
356
357
358
359
360
361
362
363
364
365
366
367
368
369
370
371
372
373
374
375
376
377
378
379
380
381
382
383
384
385
386
387
388
389
390
391
392
393
394
395
396
397
398
399
400
401
402
403
404
405
406
407
408
409
410
411
412
413
414
415
416
417
418
419
420
421
422
423
424
425
426
427
428
429
430
431
432
433
434
435
436
437
438
439
440
441
442
443
444
445
446
447
448
449
450
451
452
453
454
455
456
457
458
459
460
461
462
463
464
465
466
467
468
469
470
471
472
473
474
475
476
477
478
479
480
481
482
483
484
485
486
487
488
489
490
491
492
493
494
495
496
497
498
499
500
501
502
503
504
505
506
507
508
509
510
511
512
513
514
515
516
517
518
519
520
521
522
523
524
525
526
527
528
529
530
531
532
533
534
535
536
537
538
539
540
541
542
543
544
545
546
547
548
549
550
551
552
553
554
555
556
557
558
559
560
561
562
563
564
565
566
567
568
569
570
571
572
573
574
575
576
577
578
579
580
581
582
583
584
585
586
|
# README.ldap -*- org -*-
#+TITLE: How to use LDAP with GnuPG
#+AUTHOR: GnuPG.com
#+DATE: 2021-09-01
#
# The following comment lines are for use by Org-mode.
#+EXPORT_FILE_NAME: gnupg-and-ldap
#+LANGUAGE: en
#+OPTIONS: H:3 num:t toc:t \n:nil @:t ::t |:t ^:{} -:t f:t *:t TeX:t LaTeX:t skip:nil d:(HIDE) tags:not-in-toc
#+HTML_HEAD: <link rel="stylesheet" type="text/css" href="https://gnupg.org/share/site.css" />
#+LATEX_CLASS: article
#+LATEX_CLASS_OPTIONS: [a4paper,11pt]
#+LATEX_HEADER: \usepackage{a4wide}
#+LATEX_HEADER_EXTRA: \parindent0mm
#+STARTUP: showall
* How to use LDAP with GnuPG
In GnuPG the handling of LDAP is done by its Dirmngr component. This
is due to the architecture of the system where Dirmngr is the sole
process responsible for network related tasks. Network access is
required for:
- CRL fetching and caching for S/MIME
- OCSP checking
- S/MIME (X.509) certificate search via LDAP
- OpenPGP keyserver access (HTTP, LDAP, etc.)
- Checking for software updates (if enabled)
In the following we describe how S/MIME and OpenPGP certificate search
is implemented. If you want to skip this background information feel
free to continue with the next section where LDAP installation and
configuration is described. In any case we need to explain a few
terms used with LDAP:
- DIT :: /Directory Information Tree/ also known as /naming context/.
This is is often referred to as the /LDAP directory/. It is
where the data for a single organization described by a DNS
name is stored (e.g. "example.org").
- DN :: /Distinguished Name/ is the key for an entry in the DIT. It
is a similar concept as used in the DNS system.
- RDN :: /Relative Distinguished Name/ is a component or part of a
DN. For example the DN "cn=admin,dc=example,dc=com" consist
of the 3 RDNs "cn=admin", "dc=example", and "dc=com". Each
RDN has a name (e.g. "cn" for /common name/ or "dc" for
/domain component/) and a values (e.g. "admin").
- LDIF :: /LDAP Data Interchange Format/ is a description for the
human readable data exchange format used with LDAP.
** OpenPGP
To serve OpenPGP certificates via LDAP a dedicated schema needs to be
installed. The schema supported by GnuPG was originally defined by
PGP Inc. in the end of the 1990ies. This is today still the schema
installed on LDAP servers for access by PGP or GnuPG. However, this
schema has a couple of deficits which need to be fixed. For that
reason we have defined additional attributes. These new attributes
eventually allow to lookup certificates by their fingerprints and not
just by the shorter and thus non-unique Key-ID. The new schema also
supports storing of information on the subkeys and the UTF-8 encoded
mail addresses. Current versions of GnuPG do not yet make use of
these new attributes but for new LDAP installations it is highly
recommended to use the new schema so that a future version of the
software can make use if these attributes.
Note that the OpenPGP certificates are stored in the DIT under a
separate organizational unit using the long Key-ID to distinguish
them. An example for such an DN is:
: pgpCertID=63113AE866587D0A,ou=GnuPG Keys,dc=example,dc=com
or for Active Directory
: cn=C312[...]0A,cn=GnuPG Keys,dc=example,dc=com
This design means that entries stored under "GnuPG Keys" are not
connected to the users commonly found on an LDAP server. This allows
to store arbitrary OpenPGP certificates in the directory and is
commonly used to make the certificates of external communication
partners easily available.
** S/MIME
Standard X.509 LDAP semantics apply for S/MIME certificate search.
The current version of Dirmngr (2.2.23) supports 3 pattern formats
which are translated from GnuPG's User-ID syntax, as given to the gpg
and gpgsm commands, to the LDAP syntax:
- Mail :: Indicated by a leading left angle and translated to the
query:
: "<ADDRSPEC>" -> "mail=ADDRSPEC"
- Subject DN :: Indicated by a leading slash. The DN is formatted
according to RFC-2253 rules and thus directly usable
for an LDAP query.
- Substring search :: If no other syntax matches or the pattern is
prefixed with an asterisk the User-ID is translated to:
: "USERID" -> "(|(sn=*USERID*)(|(cn=*USERID*)(mail=*USERID*)))"
or in other word a substring search on the serial-number, the
common-name, and the mail attribute is done.
The result is expected to be in one of the attributes
"userCertificate", "cACertificate", or "x509caCert". In cases where
we are looking for the issuer certificate only "cACertificate" is
used. "ObjectClass=*" is always used a filter.
Note: The attribute "mail" with the OID 0.9.2342.19200300.100.1.3 was
originally defined with this OID under the name "rfc822Mailbox" using
a different although similar syntax. Take care: This is not an UTF-8
encoded mail address and in theory GnuPG should use IDN mapping here.
However, it is questionable whether any real world installation
would be able to handle such a mapping.
* How to install OpenLDAP
To install a standard LDAP server to provide S/MIME certificate lookup
follow the instructions of your OS vendor. For example on Debian
based systems this is:
: apt-get install slapd ldap-utils libsasl2-modules
Follow the prompts during installation, set an initial admin password,
and, most important, the domain you want to serve. Note that we use
"example.com" in following. If you ever need to change the
configuration on a Debian based system you can do so by running
: dpkg-reconfigure slapd
Serving LDAP requests for S/MIME (X.509) certificates will then work
out of the box. Use your standard tools to maintain these
entries. Some hints on how to manually add certificates can be found
below in the section "Useful LDAP Commands".
Please read on if you want to serve also OpenPGP certificates.
** Installation of the OpenPGP Schema
Assuming a standard OpenLDAP installation, it is easy to add a new
schema to store OpenPGP certificate. We describe this now step by
step.
First you need to download the two LDIF files
- https://gnupg.org/misc/gnupg-ldap-schema.ldif
- https://gnupg.org/misc/gnupg-ldap-init.ldif.
As administrator (root) on your LDAP server use the command
: ldapadd -v -Y EXTERNAL -H ldapi:/// -f ./gnupg-ldap-schema.ldif
to install the schema. The options given to the ldapadd tool are:
- -v :: Given some diagnostic output (be verbose). To be even more
verbose you may use =-vv= or =-vvv=. The diagnostics are
written to stdout.
- -Y :: Specify the authentication mechanism. Here we use =EXTERN=
which is in this case local socket based authentication
(ldapi).
- -H :: The URL to access the LDAP server. Only scheme, host, and
port are allowed. In our case we use =ldapi:///= to request
a connection on the standard OpenLDAP socket (usually this is
=/var/run/slapd/ldapi=).
- -f :: Specify a file with data to add to the directory. The file
used here is the specification of the keyserver schema. If
this option is not used ldapadd expects this data on stdin.
The new schema should now be installed. Check this by using this
command:
: ldapsearch -Q -Y EXTERNAL -L -H ldapi:/// \
: -b 'cn=schema,cn=config' cn | grep cn:
(on Unix the backslash indicates that the line is continued with the
next line)
The options not used by ldapsearch which have not yet been explained
above are:
- -Q :: Be quiet about authentication and never prompt.
- -b :: Specify the search base. In this case we want the internal
OpenLDAP schema which stores the server's own configuration.
The final argument =cn= restricts the output to the DN and the CN
attribute; the grep then shows only the latter. With a freshly
installed OpenLDAP system you should get an output like:
#+begin_example
cn: schema
cn: {0}core
cn: {1}cosine
cn: {2}nis
cn: {3}inetorgperson
cn: {4}gnupg-keyserver
#+end_example
This tells you that the keyserver schema has been installed under (in
this case) the index "{4}".
The next step is to connect the new schema with your DIT. This means
that entries to actually store the certificates and meta data are
created. This way GnuPG will be able to find the data. For this you
need to edit the downloaded file =gnupg-ldap-init.ldif= and replace
all the RDNs with name "dc" with your own. For example, in our own
LDAP we would change
: dn: cn=PGPServerInfo,dc=example,dc=com
to
: dn: cn=PGPServerInfo,dc=gnupg,dc=com
and do that also for the other 3 appearances of the "dc" RDNs. In case
you use a 3-level domain, add another "dc" in the same way you did when
setting up OpenLDAP. With that modified file run
: ldapadd -v -x -H ldapi:/// -D 'cn=admin,dc=example,dc=com' \
: -W -f ./gnupg-ldap-init.ldif
Remember to change the "dc" RDNs also here to what you actually use.
We use simple authentication by means of these options:
- -x :: Use simple authentication
- -D :: The Bind-DN used to bind to the LDAP directory
- -W :: Ask for the admin's passphrase. You may also use a lowercase
=-w= followed by the passphrase but that would reveal the
passphrase in the shell's history etc.
All users with access right to the LDAP server may now retrieve
OpenPGP certificates. But wait, we also need a user allowed to insert
or update OpenPGP certificates. Choose a useful name for that user
and create a file =newuser.ldif=. In our example domain we name that
user "LordPrivySeal" and thus the file is:
#+begin_src
dn: uid=LordPrivySeal,ou=GnuPG Users,dc=example,dc=com
objectClass: inetOrgPerson
objectClass: uidObject
sn: Lord Keeper of the Privy Seal
cn: Lord Privy Seal
userPassword: {SSHA}u6oxl9ulaS57RPyjApyPcE7mNECNK1Tg
#+end_src
The =userPassword= has been created by running
: /usr/sbin/slappasswd
entering the password, and paste the output into the file (the
password used in the above example is "abc").
Now run
: ldapadd -v -x -H ldapi:/// -D 'cn=admin,dc=example,dc=com' \
: -W -f ./newuser.ldif
On the password prompt enter the admin's password (not the one of the
new user). Note that the user is created below the "GnuPG Users"
organizational unit and not in the standard name space. Thus this is
a dedicated user for OpenPGP certificates.
See below how you can list the entire DIT. With
a fresh install you should see these DNs:
#+begin_example
dn: dc=example,dc=com
dn: cn=admin,dc=example,dc=com
dn: cn=PGPServerInfo,dc=example,dc=com
dn: ou=GnuPG Keys,dc=example,dc=com
dn: ou=GnuPG Users,dc=example,dc=com
dn: uid=LordPrivySeal,ou=GnuPG Users,dc=example,dc=com
#+end_example
Finally we need to give all users read access to the server's database
and allow an authenticated user to modify the database. To do this
you need to figure out the used database; run the command
: ldapsearch -Q -Y EXTERNAL -H ldapi:/// -b 'cn=config' dn | grep olcDatabase=
which should give you a list like this:
#+begin_example
dn: olcDatabase={-1}frontend,cn=config
dn: olcDatabase={0}config,cn=config
dn: olcDatabase={1}mdb,cn=config
#+end_example
The first two databases are for internal purposes, the last one is our
database. Now create a file =grantaccess.ldif= with this content:
#+begin_example
dn: olcDatabase={1}mdb,cn=config
changetype: modify
replace: olcAccess
olcAccess: {0} to dn.subtree="dc=example,dc=com"
by dn.regex="^uid=LordPrivySeal,ou=GnuPG Users,dc=example,dc=com" write
by * read
#+end_example
As usual replace all "dc=example,dc=com" accordingly. Take care not
to insert a blank line anywhere. The first line needs to give the DN
of the database as determined above. Excute the rules from that file
using the command:
: ldapmodify -Q -Y EXTERNAL -H ldapi:/// -f grantaccess.ldif
Now all users have read access and the user LordPrivySeal has write
access. In case you want to give several users permissions to update the
keys replace the regex line in =grantaccess.ldif= with
: by dn.regex="^uid=([^,]+),ou=GnuPG Users,dc=example,dc=com" write
(take care to insert two spaces at the begin of the line.) Then
create those users below the RDN "ou=GnuPG Users".
That's all you need to do at the server.
** Configuration for GnuPG
The easiest way to enable LDAP for S/MIME is to put
#+begin_src
keyserver ldap.example.com::::dc=example,dc=com:
#+end_src
into =gpgsm.conf=. If you prefer to use a dedicated configuration
file you can do this with dirmngr by adding a line
: ldap.example.com::::dc=example,dc=com:
to =dirmngr_ldapservers.conf=.
Assuming you want to use the machine running the LDAP server also to
maintain OpenPGP certificates, put the following line into the
=dirmngr.conf= configuration of a dedicated user for this task:
#+begin_src
keyserver ldapi:///????bindname=uid=LordPrivySeal
%2Cou=GnuPG%20Users%2Cdc=example%2Cdc=com,password=abc
#+end_src
(Enter this all on one line; "%2C" directly at the end of "Seal")
That is a pretty long line with weird escaping rules. Just enter it
verbatim but replace the "dc" RDNs accordingly. Remember that =ldapi=
uses local socket connection instead of TCP to connect to the server.
The password given in that file is the password of the OpenPGP
maintainer (LordPrivySeal). Use appropriate permissions for that
file to make it not too easy to access that password. See the GnuPG
manual for other ways to configure an LDAP keyserver.
With that configuration in place you may add arbitrary OpenPGP keys to
your LDAP. For example user "[email protected]" sends you a key and
asks to insert that key. If you feel comfortable with that you should
first check the key, import it into your local keyring, and then send
it off to your LDAP server:
: gpg --show-key < file-with-joes-key.asc
Looks good? Note the fingerprint of the key and run
: gpg --import < file-with-joes-key.asc
: gpg --send-keys FINGERPRINT
That's all. If you want to work from a different machine or use the
Kleopatra GUI you need to make sure that ldaps has been correctly
configured (for example on the machine =ldap.example.org=) and you
need to use this keyserver line:
#+begin_src
keyserver ldaps://ldap.example.com/????bindname=uid=LordPrivySeal
%2Cou=GnuPG%20Users%2Cdc=example%2Cdc=com,password=abc
#+end_src
(Enter this all on one line; "%2C" directly at the end of "Seal")
The easier case is the configuration line for anonymous users which is
a mere
#+begin_src
keyserver ldaps://ldap.example.com
#+end_src
This assumes that you have a valid TLS server certificate for that
domain and ldaps is enabled on the server.
* Useful OpenLDAP Commands
** List the entire DIT
To list the entire DIT for the domain "example.com" use this command:
: ldapsearch -Q -Y EXTERNAL -LLL -H ldapi:/// -b dc=example,dc=com dn
This lists just the DNs. If you need the entire content of the DIT
leave out the "dn" argument. The option "-LLL" selects useful
formatting options for the output.
** Insert X.509 Certficate
If you don't have a handy tool to insert a certificate via LDAP you
can do it manually. First put the certificate in binary (DER) format
into a file. For example using gpgsm:
: gpgsm --export [email protected] >berta.crt
Then create a file =addcert.ldif=:
#+begin_example
dn: CN=Berta Boss,dc=example,dc=com
objectclass: inetOrgPerson
cn: Berta Boss
sn: Boss
gn: Berta
uid: berta
mail: [email protected]
usercertificate;binary:< file:///home/admin/berta.crt
#+end_example
(Note that an absolute file name is required.)
Finally run
: ldapadd -x -H ldapi:/// -D 'cn=admin,dc=example,dc=com' -W -f adduser.ldif
** Setup TLS certificates
Create a file =tlscerts.ldif=:
#+begin_example
dn: cn=config
changetype: modify
replace: olcTLSCACertificateFile
olcTLSCACertificateFile: /etc/ssl/certs/Example.com-Root-CA.pem
-
replace: olcTLSCertificateFile
olcTLSCertificateFile: /etc/ssl/mycerts/ldap.example.com.pem
-
replace: olcTLSCertificateKeyFile
olcTLSCertificateKeyFile: /etc/ssl/private/ldap.example.com.key
#+end_example
Make sure that the user under which slapd is running has access to all
these files. The key file should only be readable by that user or
group. Then run
: ldapmodify -v -H ldapi:// -Y EXTERNAL -f tlscerts.ldif
In case you run into a the error message “Other (e.g., implementation
specific) error (80)” check the file permissions, restart slapd so
that it takes up a group modification you did, check that the order of
the item is exactly as given above.
For a quick test whether this works use this command:
: LDAPTLS_CACERT=/etc/ssl/certs/Example.com-Root-CA.pem \
: ldapwhoami -v -H ldap://ldap.example.com -ZZ -x
(-ZZ enforces the use of STARTTLS)
# Note: To enable the legacy ldap-over-tls put "ldaps:///" into the
# list of URLs give to the slapd option -h. For example:
#
# slapd -h "ldap:/// ldaps:/// ldapi:///" ...
#
# To test this use
#
# LDAPTLS_CACERT=/etc/ssl/certs/Example.com-Root-CA.pem \
# ldapwhoami -v -H ldaps://ldap.example.com -x
#
If you use a custom Root-CA certificate you need to copy it to all
clients as well. On a Debian system you would do this:
: cp Example.com-Root-CA.pem \
: /usr/local/share/ca-certificates/Example.com-Root-CA.crt
: update-ca-certificates
Note that Debian expects the suffix ".crt" even though the certificate
needs to be in PEM format. To check whether the certificate is usable
and you have installed GnuPG 2.3 you may use
: gpgsm --show-certs /etc/ssl/certsca-certificates.crt | less
** Change RootDN Password:
Create temporary file named =passwd.ldif=:
#+begin_src
dn: olcDatabase={1}mdb,cn=config
changetype: modify
replace: olcRootPW
olcRootPW: XXXX
#+end_src
For XXXX insert the output of slappasswd and run
: ldapmodify -Q -Y EXTERNAL -H ldapi:/// -f passwd.ldif
followed by
: ldappasswd -x -D cn=admin,dc=example,dc=com -W -S
and enter the new and old password again.
** Show ACLs
: ldapsearch -Q -Y EXTERNAL -H ldapi:/// -b 'cn=config' olcAccess
** Show a list of databases
: ldapsearch -Q -Y EXTERNAL -H ldapi:/// -b 'cn=config' | grep ^olcDatabase:
** Change the log level
To debug access problems, it is useful to change the log level:
: printf "dn: cn=config\nchangetype: %s\nreplace: %s\n%s: %s\n" \
: modify olcLogLevel olcLogLevel ACL | ldapadd -Q -Y EXTERNAL -H ldapi:///
to revert replace "ACL" by "none".
* How to use with Active Directory
** Extending the AD Schema
The Active Directory on Windows is actually an LDAP server but
configuration differs from OpenLDAP. The used schema is the same but
the data objects are slighly different. To extend the schema the
LDIF format is used but with variants of the files used for OpenLDAP.
Thus please download these two files:
- [[https://gnupg.org/misc/gnupg-ldap-ad-schema.ldif]]
- [[https://gnupg.org/misc/gnupg-ldap-ad-init.ldif]].
*Important*: Backup your Active Directory before you extend the
schema. There are *no ways to revert changes* made to a schema. You
should also first try this all on a test system and not on a
production system.
To extend the schema become Adminstrator on your Primary Domain
Controller and open a shell (Command Prompt). Copy the above
mentioned ldif files to your working directory and run the following
command:
: ldifde -i -f gnupg-ldap-ad-schema.ldif
: -c "DC=EXAMPLEDC" "#configurationNamingContext"
Note that this is a single line (for an LDS installation you need to
add more options like =-s localhost=). If the command succeeds the
schema has been extended to store OpenPGP keys at a well known
location. The next step is to provide information and space in the
tree. This is done similar to the above, namely:
: ldifde -i -v -f gnupg-ldap-ad-init.ldif
: -c "DC=EXAMPLEDC" "#defaultNamingContext"
You may now check your work with ADSI (enter "adsiedit"). Compare
with this [[https://gnupg.org/blog/img/ad-with-gnupg-schema.png][screenshot]] and notice the two marked entries.
The last step is to setup permissions. This depends on your
policy. Here we assume that all authenticated users get read access
to all OpenPGP keys and only certain users may insert or update those
keys.
What you need to do in all cases is to give the group /Everyone/ read
access to the =CN=PGPServerInfo= object. This allows the
clients to notice that the schema has been installed and where to look
further.
The actual keys will be stored under =CN=GnuPG Keys=. Thus give all
users of the /AuthenticatedUsers/ group read access and use the
Advanced button to set /Applies to/ to /This object and all descendant
objects/.
To insert and update keys, use a group or users and give them
permissions for =CN=GnuPG Keys= to /Read/, /Write/, /Create all child
objects/, and /Delete all child objects/. As above make sure
that these permissions apply to /This object and all descendant
objects/.
In case you want to access the keys also from non-Windows boxes, it is
probably best to create a dedicated guest user for read access.
** Using GnuPG with AD
Using the Active Directory is really easy since GnuPG 2.2.26: You only
need to put
: keyserver ldap:///
into =dirmngr.conf= and Windows takes care of authentication. Note
that we use 3 slashes and not ldaps because AD takes care of
protecting the traffic. If you use an LDS configure this
: keyserver ldap://mykeyserver.example.org/????gpgNtds=1
this will use the LDS at the given server (add a port if required) and
uses the AD for authentication.
GnuPG can also be advised to consult this configured AD or LDS similar
to a Web Key Directory (WKD). For this put
: auto-key-locate local,ntds,wkd
into =gpg.conf= so that a missing key is first looked up in the AD or
LDS before a WKD query is done.
|