[Freeipa-devel] DNSSEC support design considerations: key material handling

Petr Spacek pspacek at redhat.com
Tue Jul 16 15:15:02 UTC 2013


On 15.7.2013 21:07, Simo Sorce wrote:
> On Mon, 2013-07-15 at 16:58 +0200, Petr Spacek wrote:
>> The remaining part is mostly about key management.
>>
>> Following text mentions 'DNSSEC keys' many times, so I tried to summarize how
>> keys are used in DNSSEC. Feel free to skip it.
>>
>> == DNSSEC theory ==
>>
>> Each zone has *at least* two key pairs. They are called Key Signing Key (KSK,
>> the first key pair) and Zone Signing Key (ZSK, the second key pair).
>>
>> - *Parent* zone contains a copy of public part of the KSK.
>> - Zone itself contains public part of ZSK (and KSK).
>> - Client uses public part of KSK (obtained from secure parent zone) for ZSK
>> verification.
>> - ZSK is used for signing of the real data in the zone (i.e. generating RRSIG
>> records) and verification on client side.
>>
>> Each key and signature contains key-id, so one zone can be signed by multiple
>> KSKs and ZSKs at the same time. This solves the key roll over problem.
>>
>> Each key contains this set of timestamps:
>> Created, Revoke - self descriptive :-)
>> Publish - public part of the key will be visible in zone after this time
>> Active - new signatures with this key can be generated after this time
>> Inactive - new signatures with this key cannot be generated after this time
>> Delete - public part of the key will deleted from the zone after this time
>>
>> NIST says [1] that KSK should be changed ~ each 1-3 years (it requires change
>> in parent zone) and ZSK should be changed ~ each 1-3 months.
>>
>> The recommendation says [1] that zone should have two ZSKs: One Active (used
>> for signature generation) and second only Published (ready for roll over in
>> case of emergency/when the first key pair expires). This mitigates problems
>> with caches and stale key material during roll-over.
>>
>> BIND 9 can do signature maintenance/ZSK key roll over automatically. It needs
>> only keys stored in files (with proper timestamps) and all signatures will be
>> generated & removed when the right time passes.
>
> Is there any place I can read about the format and requirements of these
> files ?
There is no single format, because it is algorithm-dependent. See below. AFAIK 
it is nothing supported by OpenSSL, but I can be wrong.

>> KSK has to be rolled over manually because it requires changes in parent zone.
>> (It could be automated for sub-zones if their parent zone is also managed by
>> the same IPA server.)
>
> Is there any provision for using DNSSEC with private DNS deployments ?
Yes, it is. DNSSEC supports 'Islands of Security' [Terminology]: DNS resolvers 
can be configured with 'trust anchors' explicitly. E.g. 'trust domain 
example.com only if it is signed by /this/ key, use root key for rest of the 
Internet' etc.

[Terminology] http://tools.ietf.org/html/rfc4033#section-2

> Or is this going to make sense only for IPA deployments that have valid
> delegation from the public DNS system ?
>
> Hmmm I guess that as long as the KSK in the 'parent' zone is imported
> properly a private deployment of corp.myzone.com using the KSK of
> myzone.com will work just fine even if corp.myzone.com is not actually
> delegated but is a private DNS tree ?
> Or is that incorrect ?

AFAIK there *has to be* delegation via DS record [Delegation Signer, DS] from 
the parent, but IMHO it could work if only the public key for internal zones 
is published (without any delegation to internal name servers etc.). I didn't 
try it, so 'here be dragons'.

Normally it should work this way:
. (root zone is signed with well known key)
   - root contains DS record for com.
   - DS contains hash of the public key used in com. domain

com.
   - DNSKEY record contains whole public key for domain com.
   - key is accepted only if hash of the key matches DS record from parent (.)
   - DS record for example.com. is stored in com.

example.com.
   - DNSKEY record contains whole public key for domain example.com.
   - the key is accepted only if hash of the key matches DS record from parent 
(com.)

etc.

Client walks from the root zone down to the desired record and verifies 
signatures with keys obtained from DNSKEY record. The DNSKEY record itself has 
to be authenticated by DS -> DNSKEY -> DS -> DNSKEY -> ... -> DNSKEY chain 
(from root down to the zone).

Yes, publishing of DS record creates information leak - about existence of a 
sub-domain - but this information leaks anyway in e-mail headers etc. IMHO it 
is much better than messing with private Trust Anchors etc.

[DS] http://tools.ietf.org/html/rfc4034#section-5


>> == End of DNSSEC theory ==
>>
>>
>>
>> 1) How will we handle generation of key pairs? How will externally generated
>> keys be imported?
>>
>> Personally, I would start with 'classical' command line utilities like
>> dnssec-keygen etc. and extend 'ipa' tool to import generated keys. (Import =
>> read keys from text files and create appropriate attributes to LDAP.)
>
> If you mean to do this as part of the ipa-dns-install script or
> additional script (eg ipa-dnssec-enable) I am fine. I am not ok with
> asking admins to manually run these commands.
Okay. I meant something like extension of 'ipa' command.

>> Initial key generation is closely related to the question how should we handle
>> (periodic) key regeneration? (e.g. "Generate new ZSK each month.")
>
> We only really need to generate (or import) the KSK of the parent zone,
It seems that there is slight misunderstanding. KSK is the 'master key' for 
particular zone. This master key (KSK) signs other keys (ZSKs) and data are 
signed by ZSKs.

It works in the same way as key generation in PKI:
The holder (e.g. company domain, example.com) generates key pair and sends the 
public part (in our case the hash of the public key) to the authority (to the 
parent zone).

Parent should never get private key, so there is nothing to import from 
parent. I.e. we should create a new zone, generate KSKs, generate hashes and 
send hashes to the administrator of the parent zone. (I.e. generate text with 
explanation and values to send to the parent's admin.)

> our code should be able to generate any other key, and sign it.
>
>> Is it okay to use normal cron job to handle the key generation? I.e. to call
>> dnssec-keygen with proper parameters each month and store the result in LDAP?
>
> No, the problem is that we need to define 'who' generates the keys.
> Remember FreeIPA is a multimaster system, we cannot have potentially
> conflicting cron jobs running on multiple servers.
Right. It sounds like the CRL generation problem. Should we do the same for 
DNSSEC key regeneration? I.e. select one super-master and let it to handle key 
regeneration? Or should we find some more robust solution? I'm not against any 
of these possibilities :-)

>> Or should we teach certmonger to take care of DNSSEC keys? Certmonger would
>> have to call dnssec-keygen and to do some IPA calls. (I assume that key
>> parsing and import will be handled by IPA framework.)
>
> certmonger might have the same issue as a cronjob, how do we know
> *which* one of 3 DNS server should run the updating job ?
>
> Should we just leave it to chance and the first win ? What if 2 end up
> trying to create new keys at exactly the same time ?
>
>> We can postpone the key management for the first version and just provide
>> interface for key removal and import from file.
>
> Well all this key management will be a FreeIPA issue, from the
> bind-dyndb-ldap development pov we need to provide the mechanism and can
> certainly defer the key management part, but we will not be able to
> offer this feature until that is done.
I agree. I didn't realize how complex the key management part will be.

>> 2) Second question is how and where keys should be stored. AFAIK BIND 9
>> expects that keys will be stored in file system: One key pair as two files in
>> specified directory. We probably want to store keys in LDAP, as usual.
>>
>> My proposal is to represent each key pair by object with new class
>> idnsDNSSECKey. This 'key pair object' will be stored inside zone container. E.g.
>> DNS zone = idnsname=ipa.test,cn=dns,dc=ipa,dc=test
>> Key pair = cn=005+01908,idnsname=ipa.test,cn=dns,dc=ipa,dc=test
>>
>> Private key is represented by opaque blob (size ~ 1-2 kiB), so octetString
>> could be the right syntax:
>> attributetypes: ( x.x.x.x.x NAME 'idnsSecPrivateKey' SYNTAX
>> 1.3.6.1.4.1.1466.115.121.1.40 SINGLE-VALUE )
>
> Is this just a key ? Or does it contain further data ?
It contains some meta data (mainly timestamps): created on/public from/active 
from/valid to/revoked/key type (KSK/ZSK)/algorithm.

>> Public key can be represented with normal DNSKEY record (size ~ 200-500 B), so
>> it would be possible to use normal DNSKEY attribute. I see two problems with
>> this approach:
>> - DNSKEY record (= attribute) is multi-valued by definition, but only one
>> public key can be present in a key pair.
>> - DNSKEY records will be managed automatically by BIND so we don't want to let
>> users to mess with them directly. DNSKEYRecord attribute is not defined at the
>> moment and I'm not willing to define it now.
>>
>> For these reasons I think that we can define new public key attribute in the
>> same way as private key attribute:
>> attributetypes: ( x.x.x.x.x NAME 'idnsSecPublicKey' SYNTAX
>> 1.3.6.1.4.1.1466.115.121.1.40 SINGLE-VALUE )
>>
>> The resulting object class could be:
>> objectClasses: ( x.x.x.x.x NAME 'idnsSecKeyPair' DESC 'DNSSEC key pair' SUP
>> top STRUCTURAL MUST ( cn $ idnsSecPrivateKey $ idnsSecPublicKey ) )
>
> Will bind read these attributes ?
> Or will we have to dump these values into files via bind-dyndb-ldap for
> bind9 to read them back ?
AFAIK it has to be in files: Private key in one file and public key in the 
other file. I can't find any support for reading private keys from buffers.

>> CN attribute is user readable key name. It could be anything. BIND's syntax
>> follows (text copied from dnssec-keyfromlabel):
>> This is an identification string for the key files: String of the form
>> "Knnnn.+aaa+iiiii":
>> - nnnn is the key name (zone name)
>> - aaa is the numeric representation of the algorithm
>> - iiiii is the key identifier (or footprint)
>>
>> Naturally, we can omit leading "K" and zone name, because we know the name
>> from parent object in the LDAP/DIT. Also, it could be nice to indicate the
>> type of the key - KSK or ZSK.
>
> ack, should we have an explicit attribute that tells us what type it
> is ?
May be, we will see. It is possible that we will need to store key algorithm 
and key ID explicitly for some reason.

I'm still not sure that I understand to all aspects of key management in BIND.

>> Attribute idnsSecPrivateKey should be readable only by DNS admins (and DNS
>> servers :-). I'm not sure if we should make restrict read access even more. Is
>> there a valid reason for admin to read the blob? I don't know, but admin can
>> read the file on disk anyway ...
>
> One weak reason to allow read by admins would be to allow them to
> migrate away, but I do not like to put these keys completely unprotected
> in LDAP. Given bind has a keytab I was thinking we may want to encrypt
> these keys with the DNS long term key, however this complicates the code
> slightly in 2 ways:
> 1. we can have multiple DNS Servers (ie multiple keys)
> 2. we need to allow for roll-over

I see two more problems:
3. it would make Kerberos required (now the plugin doesn't require Kerberos)
4. we use SASL but I think that your approach would require direct 
manipulation with keytab

> To simplify the matter we would have to use a 'master key' that encrypts
> all signing keys and is made available to DNS servers encrypted with
> their keys.
>
> Master key needs to allow for roll over in case it is compromised. But
> we could deal with it by simply rolling also all DNS keys and encrypting
> the new ones with the new key. After all if the key was compromised we
> must assume all DNs signing keys may have been compromised so a full
> roll-over is necessary. This simplifies the problem because it means we
> will never need to store the same DNS signing key encrypted with
> multiple 'master keys'.
>
> A master key also allows for easy addition/removal of DNS servers as it
> needs to be re-encrypted only once when a new DNS is added (or removed
> and readded), and a server removal is just a delete operation.

Oooo, lots of fun. Are you aware of any abstraction layer which could all the 
magic for us? Something from OpenSSL/SASL/GSSAPI? I didn't mention Dogtag 
because dependency on Dogtag might become my nightmare... :-)

>>   From user interface point of view, key pairs are bit hard to deal with.
>> Private key format is algorithm-dependent, so the only universal way to get
>> standardized fields like valid-from/active-from/valid-to/revoked timestamps
>> etc. is to call parser from bind-libs.
>
> Are these parsers available in public libs ?
It seems that all necessary parts are available via package bind-libs, 
/usr/include/bind9/dst/dst.h.

> Should we add these attributes explicitly in the 'idnsSecKeyPair'
> objetclass instead and reconstruct the private key file from there ?
> Or would that risk being incompatibile with a future new key type ?
That is exactly why I proposed the 'blob' approach. Each algorithm needs 
different values, so RSA and DSA key formats differ. See attachments - these 
files were written by dnssec-keygen for RSASHA1 and DSA.

Formats are *similar* at the moment, but the problem is that parsers for each 
algorithm can diverge in the future.

> If so should we really split key material in 2 attributes? Or should we
> rather just load the full file content in a single attribute as an
> opaque blob ?
BIND 9 stores public and private keys separately in two files, so I would 
imitate it's approach - with two separate attributes.

>> 3) How will the configuration be stored?
>> Parameters are:
>> - DNSSEC enabled/disabled for one zone or globally - proposal: add a new
>> boolean attribute idnsSecInlineSigning to zone and global config object
>
> why not simply iDNSSECenabled: TRUE/FALSE ?
I would like to imitate BIND's config - we plan to do the same thing as BIND's 
option 'inline-signing'.

BIND will do signing for us, but at some point in the future we could decide 
to do signing ourselves etc. More specific name prevents confusion when we 
need to change behaviour.

>> - NSEC3 parameters - proposal: use standard NSEC3PARAM record in the zone
>
> What are these ?
Short answer:
http://www.simpledns.com/help/v52/rec_nsec3param.htm

Long answer:
DNS Security (DNSSEC) Hashed Authenticated Denial of Existence
http://tools.ietf.org/html/rfc5155#section-4

>> The rest of the configuration options are related to the key management
>> problem. We need to know:
>> - how many key pairs (e.g. 2 KSKs, 2 ZSKs)
>
> Shouldn't we allow an arbitrary number ? Does bind have strict limits ?
Yes, arbitrary number sounds fine. 2 + 2 was just an example.

>> - when (e.g. generate new key pair 30 days before active key expires)
>
> probably needs to be tunable. new attribute ?
>
>> - of which key types (KSK or ZSK)
>> - with which algorithms
>> - with which key lengths
>> should be generated. Note that we need to store configuration about X KSKs and
>> Y ZSKs.
>
> seem all of these needs to be tunables and require their own
> attributes ?
I agree. The question is how to group the attributes to make it useful.

IMHO it should express something like this:
- I want to use 1 KSK with algorithm RSASHA1, key length 2048 bits, the key 
should be used for 1 year.
- I want to have 1 other KSK (with same parameters) ready for roll over at any 
time.
- Roll over period is 1 month. (The time required for incremental resigning 
with the new key, i.e. the time period when old and new signatures will co-exist.)

The result should be:

In time 0 (zone creation), generate 2 KSKs:
The KSK 'A' would have these timestamps:
- created = published = active from = 0 (generate signatures immediately)
- inactive = 0 + 1 year - 1 month (stop generating signatures after 11 months)
- delete = 0 + 1 year (one month was transitional period for incremental 
resigning with the new key, then delete the key 'A')

The KSK 'B' would be generated at the same time as 'A':
- created = published = 0 (publish key, but don't generate signatures)
- active from = 0 + 1 year
- inactive = 0 + 2 years - 1 month
- delete = 0 + 2 years

During the first year, all records will be signed with KSK 'A'. In time '0 + 1 
year - 1 month' KSK 'A' will become inactive and KSK 'B' will become active. 
At the same time, new KSK 'C' will be generated with following timestamps:
- created = published = 1 year - 1 month (publish key, but don't generate 
signatures)
- active from = 0 + 2 year - 1 month
- inactive = 0 + 3 years - 1 month
- delete = 0 + 3 years

All records will be re-signed using KSK 'B' during time <1 year - 1 month, 1 
year>.

In time  '0 + 1 year' all signatures were regenerated with using KSK 'B' and 
KSK 'A' will be removed.

Note that you may want to use 1 KSK with algorithm RSA and another KSK with DSA.

I'm not really sure if it makes sense. Could something like this work?

objectClasses: ( x.x.x.x.x NAME 'idnsSecKeyGroup' DESC 'DNSSEC key group' SUP 
top STRUCTURAL MUST
( cn $
   key type $ # (KSK or ZSK)
   algorithm $ # (RSA, DSA)
   key length $ # (2048)
   lifetime of the key $ # (1 year)
   roll over period $ # (1 month)
   number of active keys $ # (1)
   number of spare keys $ # (1)
  ) )

The key group could be stored as
cn=ksk-rsa, idsname=example.com, cn=dns, dc=ipa,dc=test
Keys could be stored as individual objects under
cn=id, cn=ksk-rsa, idsname=example.com, cn=dns, dc=ipa,dc=test

In usual cases it solves grouping of KSKs and ZSKs. Also, it enables us to 
define key group with RSA and another one with DSA algorithm or to migrate 
from a key group with shorter keys to a key group with longer keys.

>> Again, we can postpone the key management for the first version.
>
> We can certainly postpone certain aspects of key management at least to
> get development time down to a more quantifiable amount. But we'll not
> be able to offer DNSSEC support in FreeIPA until there is management.
>
>> 4) For future versions - do we plan to add support for PKCS#11 HSMs? BIND 9
>> can use OpenSSL for this stuff (somehow), but I didn't look into details.
>
> I think this can be certainly postponed unless it may require changes in
> the schema, in which case we may want to discuss if we need anything in
> there so that the initial code can be future-proof.

I have a crazy idea: Could OpenSSL PKCS#11 implementation help us to deal with 
the key management problems mentioned above - somehow?

I know next to nothing about PKCS#11 and related areas, but problems we met 
(like safe key storage & transport) sounds like something common.

Could we use PKCS#11 in some clever way, let OpenSSL to do the dirty work with 
key encryption/retrieval and solve HSM support and security at once?

Would it be possible to write PKCS#11 module for OpenSSL and let it to store 
keys in IPA - in some generic way? So it will solve key storage for all 
OpenSSL/PKCS#11 enabled applications and not only for bind-dyndb-ldap?

As I said, it is just crazy idea ... and I really know nothing about this area.

>> [1] http://csrc.nist.gov/publications/nistpubs/800-81r1/sp-800-81r1.pdf
>> section 9.3 Generation of Public Key-Private Key Pair (DNSSEC-OP1) page 9-5

-- 
Petr^2 Spacek
-------------- next part --------------
; This is a zone-signing key, keyid 50652, for dsa.
; Created: 20130716083717 (Tue Jul 16 10:37:17 2013)
; Publish: 20130716083717 (Tue Jul 16 10:37:17 2013)
; Activate: 20130716083717 (Tue Jul 16 10:37:17 2013)
dsa. IN DNSKEY 256 3 3 CI/K88jBpTjtAnjNfOalooVPIjwPjtpxqkP7VpuAqZnmVvOjLxnZd4y6 KcFwGFQKzwhRt4nDP/9aCl30YJwdg6/GLB9YlsAekofBqr6H7Xf6NJTP QfAF56MAH5314Bw+jjsvWIAOEYpL9Ymqjcffi9ol5w2JZnHDz2NcpL09 Sg0Bmm4lyFZdHMb1ixaoyU4tkaPurANFLy58Lk9IE4/KyXR+VMl2cYyy dlvox+N7a8QBBDE5618hofd4CoJtHKJmDn/xlMDWs0sasK0bJ1sDdFpf 5EJh54MBVzZ9/YpYGoAvZtH4Awa2RXLHd5oRKf93miQbpNCUVgXeg2LZ dqkwNskpyJ51GEBT9wXO80i2AdSxAcbAbmXqi+zVCGk4BC+A4KfKxuUW o4MQY8AsRRLWgFiZlm1+y5xFnjnQUfcgRChsoyDsSRLbbC76GQ/1gugA B437MYShyRixzLg7o77DZtyvkldG1oei70yPDI1I1FXyomm6UrjjXi+m zjPUee95cuRXGhfPVkptQev3ofBsQ3Lagw79
-------------- next part --------------
Private-key-format: v1.3
Algorithm: 3 (DSA)
Prime(p): jtpxqkP7VpuAqZnmVvOjLxnZd4y6KcFwGFQKzwhRt4nDP/9aCl30YJwdg6/GLB9YlsAekofBqr6H7Xf6NJTPQfAF56MAH5314Bw+jjsvWIAOEYpL9Ymqjcffi9ol5w2JZnHDz2NcpL09Sg0Bmm4lyFZdHMb1ixaoyU4tkaPurAM=
Subprime(q): j8rzyMGlOO0CeM185qWihU8iPA8=
Base(g): RS8ufC5PSBOPysl0flTJdnGMsnZb6Mfje2vEAQQxOetfIaH3eAqCbRyiZg5/8ZTA1rNLGrCtGydbA3RaX+RCYeeDAVc2ff2KWBqAL2bR+AMGtkVyx3eaESn/d5okG6TQlFYF3oNi2XapMDbJKciedRhAU/cFzvNItgHUsQHGwG4=
Private_value(x): GQZLYTTYtbphXYctPb/RgiL9Vqs=
Public_value(y): ZeqL7NUIaTgEL4Dgp8rG5RajgxBjwCxFEtaAWJmWbX7LnEWeOdBR9yBEKGyjIOxJEttsLvoZD/WC6AAHjfsxhKHJGLHMuDujvsNm3K+SV0bWh6LvTI8MjUjUVfKiabpSuONeL6bOM9R573ly5FcaF89WSm1B6/eh8GxDctqDDv0=
Created: 20130716083717
Publish: 20130716083717
Activate: 20130716083717
-------------- next part --------------
; This is a zone-signing key, keyid 45708, for rsasha1.
; Created: 20130716083609 (Tue Jul 16 10:36:09 2013)
; Publish: 20130716083609 (Tue Jul 16 10:36:09 2013)
; Activate: 20130716083609 (Tue Jul 16 10:36:09 2013)
rsasha1. IN DNSKEY 256 3 5 AwEAAc4kyuvD/3YdFcBa7Q65dBeejSyBpnSnkQBvZxkQcFU8rggBwFWK 3Sjx8gGR1cpOtGf5Mj3FwdG4qKutc3iPhBRGefUj0erhIpxY4d0xQXgM BZDIwz90l3KQiuod2BoFgBLdhhG+CadxbHUkcpF4CvWjkhYusmaoxALl gqobOYp7
-------------- next part --------------
Private-key-format: v1.3
Algorithm: 5 (RSASHA1)
Modulus: ziTK68P/dh0VwFrtDrl0F56NLIGmdKeRAG9nGRBwVTyuCAHAVYrdKPHyAZHVyk60Z/kyPcXB0bioq61zeI+EFEZ59SPR6uEinFjh3TFBeAwFkMjDP3SXcpCK6h3YGgWAEt2GEb4Jp3FsdSRykXgK9aOSFi6yZqjEAuWCqhs5ins=
PublicExponent: AQAB
PrivateExponent: JU+3gtDo7iH5i+VpPt8GSjgiaUnWLQsfTarcSEcXbfYbsctPWqxVt1GDchFJVuLD+IW8OD4RBLqdnOU6Hzoqt4WV9cC0Y0bi+0Oymj8D4LSvxHLkQRqwsn12IRNc/VkLuGuGDWqsRa3jvMJ3YdVWqLTI86/F6TvhJVlh7cz/AHE=
Prime1: 6cDgV1VsC2subAkgDMOLwNp6VpxP7MTq0Sulxz4pvJTKafyg18qqhs/1yS6p+crqXvcrJf3B7S/+sagdX/q1/Q==
Prime2: 4cM9JFHv5P2b9ypcgj1FU6lFm+Al+1/HBWmSQi8NNAxbgKXzlNjmVrRELPLAVCfUHhxwsb2kkIlUIQzaMGpv1w==
Exponent1: jtkRwA0x0+CSI++HqIUvuJFLRfaMWVMVdPJJgvMYKmh7Mj3yRS1S/MPFnkZoFYDNrW867SKgCkTUTtk/6lGaOQ==
Exponent2: CFG4fBEk5OxPhgEinY4Ccv3G2eKdo7C41cM5J4UyWFuoN4pl+nMvsbw80uczHSbGk0F7CaGyYb0dw4YEuEoDyw==
Coefficient: wHuchg0IJF/beCPfgtFGkayrd0grKOZtWCSRhiFVS1KH+EJJP0WQQCMaFukK8cBNm6ZDcG7Q73G7RUS95JqTvQ==
Created: 20130716083609
Publish: 20130716083609
Activate: 20130716083609


More information about the Freeipa-devel mailing list