]>
git.ipfire.org Git - thirdparty/pdns.git/blob - pdns/dnssecinfra.cc
addcab456734ec62f7c66f86b6a7efebeb0974d0
4 #include "dnsparser.hh"
7 #include "dnswriter.hh"
8 #include "dnsrecords.hh"
14 #include <boost/algorithm/string.hpp>
15 #include "dnssecinfra.hh"
16 #include "dnsseckeeper.hh"
17 #include <openssl/hmac.h>
18 #include <openssl/sha.h>
19 #include <boost/assign/std/vector.hpp> // for 'operator+=()'
20 #include <boost/assign/list_inserter.hpp>
22 #include "namespaces.hh"
24 #include "pkcs11signers.hh"
26 #include "gss_context.hh"
29 using namespace boost :: assign
;
31 DNSCryptoKeyEngine
* DNSCryptoKeyEngine :: makeFromISCFile ( DNSKEYRecordContent
& drc
, const char * fname
)
34 FILE * fp
= fopen ( fname
, "r" );
36 throw runtime_error ( "Unable to read file '" + string ( fname
)+ "' for generating DNS Private Key" );
39 while ( stringfgets ( fp
, sline
)) {
43 DNSCryptoKeyEngine
* dke
= makeFromISCString ( drc
, isc
);
44 if (! dke
-> checkKey ()) {
46 throw runtime_error ( "Invalid DNS Private Key in file '" + string ( fname
));
51 DNSCryptoKeyEngine
* DNSCryptoKeyEngine :: makeFromISCString ( DNSKEYRecordContent
& drc
, const std :: string
& content
)
55 string sline
, key
, value
, raw
;
56 std :: istringstream
str ( content
);
57 map
< string
, string
> stormap
;
59 while ( std :: getline ( str
, sline
)) {
60 tie ( key
, value
)= splitField ( sline
, ':' );
62 if ( pdns_iequals ( key
, "algorithm" )) {
63 algorithm
= pdns_stou ( value
);
64 stormap
[ "algorithm" ]= std :: to_string ( algorithm
);
66 } else if ( pdns_iequals ( key
, "pin" )) {
69 } else if ( pdns_iequals ( key
, "engine" )) {
70 stormap
[ "engine" ]= value
;
73 } else if ( pdns_iequals ( key
, "slot" )) {
74 stormap
[ "slot" ]= value
;
76 } else if ( pdns_iequals ( key
, "label" )) {
77 stormap
[ "label" ]= value
;
80 else if ( pdns_iequals ( key
, "Private-key-format" ))
83 B64Decode ( value
, raw
);
84 stormap
[ toLower ( key
)]= raw
;
86 DNSCryptoKeyEngine
* dpk
;
90 if ( stormap
. find ( "slot" ) == stormap
. end ())
91 throw PDNSException ( "Cannot load PKCS#11 key, no Slot specified" );
92 // we need PIN to be at least empty
93 if ( stormap
. find ( "pin" ) == stormap
. end ()) stormap
[ "pin" ] = "" ;
94 dpk
= PKCS11DNSCryptoKeyEngine :: maker ( algorithm
);
96 throw PDNSException ( "Cannot load PKCS#11 key without support for it" );
101 dpk
-> fromISCMap ( drc
, stormap
);
105 std :: string
DNSCryptoKeyEngine :: convertToISC () const
107 typedef map
< string
, string
> stormap_t
;
108 storvector_t stormap
= this -> convertToISCVector ();
110 ret
<< "Private-key-format: v1.2 \n " ;
111 for ( const stormap_t :: value_type
& value
: stormap
) {
112 if ( value
. first
!= "Algorithm" && value
. first
!= "PIN" &&
113 value
. first
!= "Slot" && value
. first
!= "Engine" &&
114 value
. first
!= "Label" )
115 ret
<< value
. first
<< ": " << Base64Encode ( value
. second
)<< " \n " ;
117 ret
<< value
. first
<< ": " << value
. second
<< " \n " ;
122 DNSCryptoKeyEngine
* DNSCryptoKeyEngine :: make ( unsigned int algo
)
124 makers_t
& makers
= getMakers ();
125 makers_t :: const_iterator iter
= makers
. find ( algo
);
126 if ( iter
!= makers
. end ())
127 return ( iter
-> second
)( algo
);
129 throw runtime_error ( "Request to create key object for unknown algorithm number " + std :: to_string ( algo
));
134 * Returns the supported DNSSEC algorithms with the name of the Crypto Backend used
136 * @return A vector with pairs of (algorithm-number (int), backend-name (string))
138 vector
< pair
< uint8_t , string
>> DNSCryptoKeyEngine :: listAllAlgosWithBackend ()
140 vector
< pair
< uint8_t , string
>> ret
;
141 for ( auto const & value
: getMakers ()) {
142 shared_ptr
< DNSCryptoKeyEngine
> dcke ( value
. second ( value
. first
));
143 ret
. push_back ( make_pair ( value
. first
, dcke
-> getName ()));
148 void DNSCryptoKeyEngine :: report ( unsigned int algo
, maker_t
* maker
, bool fallback
)
150 getAllMakers ()[ algo
]. push_back ( maker
);
151 if ( getMakers (). count ( algo
) && fallback
) {
154 getMakers ()[ algo
]= maker
;
157 bool DNSCryptoKeyEngine :: testAll ()
161 for ( const allmakers_t :: value_type
& value
: getAllMakers ())
163 for ( maker_t
* creator
: value
. second
) {
165 for ( maker_t
* signer
: value
. second
) {
166 // multi_map<unsigned int, maker_t*> bestSigner, bestVerifier;
168 for ( maker_t
* verifier
: value
. second
) {
170 /* pair<unsigned int, unsigned int> res=*/ testMakers ( value
. first
, creator
, signer
, verifier
);
172 catch ( std :: exception
& e
)
174 cerr
<< e
. what ()<< endl
;
184 bool DNSCryptoKeyEngine :: testOne ( int algo
)
188 for ( maker_t
* creator
: getAllMakers ()[ algo
]) {
190 for ( maker_t
* signer
: getAllMakers ()[ algo
]) {
191 // multi_map<unsigned int, maker_t*> bestSigner, bestVerifier;
193 for ( maker_t
* verifier
: getAllMakers ()[ algo
]) {
195 /* pair<unsigned int, unsigned int> res=*/ testMakers ( algo
, creator
, signer
, verifier
);
197 catch ( std :: exception
& e
)
199 cerr
<< e
. what ()<< endl
;
207 // returns times it took to sign and verify
208 pair
< unsigned int , unsigned int > DNSCryptoKeyEngine :: testMakers ( unsigned int algo
, maker_t
* creator
, maker_t
* signer
, maker_t
* verifier
)
210 shared_ptr
< DNSCryptoKeyEngine
> dckeCreate ( creator ( algo
));
211 shared_ptr
< DNSCryptoKeyEngine
> dckeSign ( signer ( algo
));
212 shared_ptr
< DNSCryptoKeyEngine
> dckeVerify ( verifier ( algo
));
214 cerr
<< "Testing algorithm " << algo
<< ": '" << dckeCreate
-> getName ()<< "' ->'" << dckeSign
-> getName ()<< "' -> '" << dckeVerify
-> getName ()<< "' " ;
218 else if ( algo
== 12 || algo
== 13 || algo
== 250 ) // ECC-GOST or ECDSAP256SHA256 or ED25519SHA512
220 else if ( algo
== 14 ) // ECDSAP384SHA384
223 throw runtime_error ( "Can't guess key size for algorithm " + std :: to_string ( algo
));
225 dckeCreate
-> create ( bits
);
227 { // FIXME: this block copy/pasted from makeFromISCString
228 DNSKEYRecordContent dkrc
;
230 string sline
, key
, value
, raw
;
231 std :: istringstream
str ( dckeCreate
-> convertToISC ());
232 map
< string
, string
> stormap
;
234 while ( std :: getline ( str
, sline
)) {
235 tie ( key
, value
)= splitField ( sline
, ':' );
237 if ( pdns_iequals ( key
, "algorithm" )) {
238 algorithm
= pdns_stou ( value
);
239 stormap
[ "algorithm" ]= std :: to_string ( algorithm
);
241 } else if ( pdns_iequals ( key
, "pin" )) {
242 stormap
[ "pin" ]= value
;
244 } else if ( pdns_iequals ( key
, "engine" )) {
245 stormap
[ "engine" ]= value
;
247 } else if ( pdns_iequals ( key
, "slot" )) {
248 int slot
= std :: stoi ( value
);
249 stormap
[ "slot" ]= std :: to_string ( slot
);
251 } else if ( pdns_iequals ( key
, "label" )) {
252 stormap
[ "label" ]= value
;
255 else if ( pdns_iequals ( key
, "Private-key-format" ))
258 B64Decode ( value
, raw
);
259 stormap
[ toLower ( key
)]= raw
;
261 dckeSign
-> fromISCMap ( dkrc
, stormap
);
262 if (! dckeSign
-> checkKey ()) {
263 throw runtime_error ( "Verification of key with creator " + dckeCreate
-> getName ()+ " with signer " + dckeSign
-> getName ()+ " and verifier " + dckeVerify
-> getName ()+ " failed" );
267 string
message ( "Hi! How is life?" );
271 for ( unsigned int n
= 0 ; n
< 100 ; ++ n
)
272 signature
= dckeSign
-> sign ( message
);
273 unsigned int udiffSign
= dt
. udiff ()/ 100 , udiffVerify
;
275 dckeVerify
-> fromPublicKeyString ( dckeSign
-> getPublicKeyString ());
276 if ( dckeVerify
-> getPublicKeyString (). compare ( dckeSign
-> getPublicKeyString ())) {
277 throw runtime_error ( "Comparison of public key loaded into verifier produced by signer failed" );
280 if ( dckeVerify
-> verify ( message
, signature
)) {
281 udiffVerify
= dt
. udiff ();
282 cerr
<< "Signature & verify ok, signature " << udiffSign
<< "usec, verify " << udiffVerify
<< "usec" << endl
;
285 throw runtime_error ( "Verification of creator " + dckeCreate
-> getName ()+ " with signer " + dckeSign
-> getName ()+ " and verifier " + dckeVerify
-> getName ()+ " failed" );
287 return make_pair ( udiffSign
, udiffVerify
);
290 DNSCryptoKeyEngine
* DNSCryptoKeyEngine :: makeFromPublicKeyString ( unsigned int algorithm
, const std :: string
& content
)
292 DNSCryptoKeyEngine
* dpk
= make ( algorithm
);
293 dpk
-> fromPublicKeyString ( content
);
298 DNSCryptoKeyEngine
* DNSCryptoKeyEngine :: makeFromPEMString ( DNSKEYRecordContent
& drc
, const std :: string
& raw
)
301 for ( makers_t :: value_type
& val
: getMakers ())
303 DNSCryptoKeyEngine
* ret
= 0 ;
305 ret
= val
. second ( val
. first
);
306 ret
-> fromPEMString ( drc
, raw
);
311 delete ret
; // fine if 0
318 bool sharedDNSSECCompare ( const shared_ptr
< DNSRecordContent
>& a
, const shared_ptr
< DNSRecordContent
>& b
)
320 return a
-> serialize ( DNSName ( "." ), true , true ) < b
-> serialize ( DNSName ( "." ), true , true );
324 * Returns the string that should be hashed to create/verify the RRSIG content
326 * @param qname DNSName of the RRSIG's owner name.
327 * @param rrc The RRSIGRecordContent we take the Type Covered and
328 * original TTL fields from.
329 * @param signRecords A vector of DNSRecordContent shared_ptr's that are covered
330 * by the RRSIG, where we get the RDATA from.
331 * @param processRRSIGLabels A boolean to trigger processing the RRSIG's "Labels"
332 * field. This is usually only needed for validation
333 * purposes, as the authoritative server correctly
334 * sets qname to the wildcard.
336 string
getMessageForRRSET ( const DNSName
& qname
, const RRSIGRecordContent
& rrc
, vector
< shared_ptr
< DNSRecordContent
> >& signRecords
, bool processRRSIGLabels
)
338 sort ( signRecords
. begin (), signRecords
. end (), sharedDNSSECCompare
);
341 toHash
. append ( const_cast < RRSIGRecordContent
&>( rrc
). serialize ( DNSName ( "." ), true , true ));
342 toHash
. resize ( toHash
. size () - rrc
. d_signature
. length ()); // chop off the end, don't sign the signature!
344 string
nameToHash ( qname
. toDNSStringLC ());
346 if ( processRRSIGLabels
) {
347 unsigned int rrsig_labels
= rrc
. d_labels
;
348 unsigned int fqdn_labels
= qname
. countLabels ();
350 if ( rrsig_labels
< fqdn_labels
) {
351 DNSName
choppedQname ( qname
);
352 while ( choppedQname
. countLabels () > rrsig_labels
)
353 choppedQname
. chopOff ();
354 nameToHash
= " \x01 *" + choppedQname
. toDNSStringLC ();
355 } else if ( rrsig_labels
> fqdn_labels
) {
356 // The RRSIG Labels field is a lie (or the qname is wrong) and the RRSIG
357 // can never be valid
362 for ( shared_ptr
< DNSRecordContent
>& add
: signRecords
) {
363 toHash
. append ( nameToHash
);
364 uint16_t tmp
= htons ( rrc
. d_type
);
365 toHash
. append (( char *)& tmp
, 2 );
366 tmp
= htons ( 1 ); // class
367 toHash
. append (( char *)& tmp
, 2 );
368 uint32_t ttl
= htonl ( rrc
. d_originalttl
);
369 toHash
. append (( char *)& ttl
, 4 );
370 // for NSEC signatures, we should not lowercase the rdata section
371 string rdata
= add
-> serialize ( DNSName ( "." ), true , ( add
-> getType () == QType :: NSEC
) ? false : true ); // RFC 6840, 5.1
372 tmp
= htons ( rdata
. length ());
373 toHash
. append (( char *)& tmp
, 2 );
374 toHash
. append ( rdata
);
380 DSRecordContent
makeDSFromDNSKey ( const DNSName
& qname
, const DNSKEYRecordContent
& drc
, int digest
)
383 toHash
. assign ( qname
. toDNSStringLC ());
384 toHash
. append ( const_cast < DNSKEYRecordContent
&>( drc
). serialize ( DNSName (), true , true ));
386 DSRecordContent dsrc
;
388 shared_ptr
< DNSCryptoKeyEngine
> dpk ( DNSCryptoKeyEngine :: make ( 5 )); // gives us SHA1
389 dsrc
. d_digest
= dpk
-> hash ( toHash
);
391 else if ( digest
== 2 ) {
392 shared_ptr
< DNSCryptoKeyEngine
> dpk ( DNSCryptoKeyEngine :: make ( 8 )); // gives us SHA256
393 dsrc
. d_digest
= dpk
-> hash ( toHash
);
395 else if ( digest
== 3 ) {
396 shared_ptr
< DNSCryptoKeyEngine
> dpk ( DNSCryptoKeyEngine :: make ( 12 )); // gives us GOST
397 dsrc
. d_digest
= dpk
-> hash ( toHash
);
399 else if ( digest
== 4 ) {
400 shared_ptr
< DNSCryptoKeyEngine
> dpk ( DNSCryptoKeyEngine :: make ( 14 )); // gives us ECDSAP384
401 dsrc
. d_digest
= dpk
-> hash ( toHash
);
404 throw std :: runtime_error ( "Asked to a DS of unknown digest type " + std :: to_string ( digest
)+ " \n " );
406 dsrc
. d_algorithm
= drc
. d_algorithm
;
407 dsrc
. d_digesttype
= digest
;
408 dsrc
. d_tag
= const_cast < DNSKEYRecordContent
&>( drc
). getTag ();
414 DNSKEYRecordContent
makeDNSKEYFromDNSCryptoKeyEngine ( const DNSCryptoKeyEngine
* pk
, uint8_t algorithm
, uint16_t flags
)
416 DNSKEYRecordContent drc
;
419 drc
. d_algorithm
= algorithm
;
422 drc
. d_key
= pk
-> getPublicKeyString ();
427 int countLabels ( const std :: string
& signQName
)
429 if (! signQName
. empty ()) {
431 for ( string :: const_iterator pos
= signQName
. begin (); pos
!= signQName
. end () ; ++ pos
)
432 if (* pos
== '.' && pos
+ 1 != signQName
. end ())
435 if ( boost :: starts_with ( signQName
, "*." ))
442 uint32_t getStartOfWeek ()
444 uint32_t now
= time ( 0 );
445 now
-= ( now
% ( 7 * 86400 ));
449 string
hashQNameWithSalt ( const NSEC3PARAMRecordContent
& ns3prc
, const DNSName
& qname
)
451 return hashQNameWithSalt ( ns3prc
. d_salt
, ns3prc
. d_iterations
, qname
);
454 string
hashQNameWithSalt ( const std :: string
& salt
, unsigned int iterations
, const DNSName
& qname
)
456 unsigned int times
= iterations
;
457 unsigned char hash
[ 20 ];
458 string
toHash ( qname
. toDNSStringLC ());
462 SHA1 (( unsigned char *) toHash
. c_str (), toHash
. length (), hash
);
463 toHash
. assign (( char *) hash
, sizeof ( hash
));
470 DNSKEYRecordContent
DNSSECPrivateKey :: getDNSKEY () const
472 return makeDNSKEYFromDNSCryptoKeyEngine ( getKey (), d_algorithm
, d_flags
);
478 DEREater ( const std :: string
& str
) : d_str ( str
), d_pos ( 0 )
485 if ( d_pos
>= d_str
. length ()) {
488 return ( uint8_t ) d_str
[ d_pos
++];
493 uint8_t first
= getByte ();
500 for ( int n
= 0 ; n
< first
; ++ n
) {
507 std :: string
getBytes ( unsigned int len
)
510 for ( unsigned int n
= 0 ; n
< len
; ++ n
)
511 ret
. append ( 1 , ( char ) getByte ());
515 std :: string :: size_type
getOffset ()
520 const std :: string
& d_str
;
521 std :: string :: size_type d_pos
;
524 void decodeDERIntegerSequence ( const std :: string
& input
, vector
< string
>& output
)
528 if ( de
. getByte () != 0x30 )
529 throw runtime_error ( "Not a DER sequence" );
531 unsigned int seqlen
= de
. getLength ();
532 unsigned int startseq
= de
. getOffset ();
537 uint8_t kind
= de
. getByte ();
539 throw runtime_error ( "DER Sequence contained non-INTEGER component: " + std :: to_string ( static_cast < unsigned int >( kind
)) );
540 len
= de
. getLength ();
541 ret
= de
. getBytes ( len
);
542 output
. push_back ( ret
);
545 catch ( DEREater :: eof
& eof
)
547 if ( de
. getOffset () - startseq
!= seqlen
)
548 throw runtime_error ( "DER Sequence ended before end of data" );
552 string
calculateHMAC ( const std :: string
& key
, const std :: string
& text
, TSIGHashEnum hasher
) {
554 const EVP_MD
* md_type
;
556 unsigned char hash
[ EVP_MAX_MD_SIZE
];
562 md_type
= EVP_sha1 ();
565 md_type
= EVP_sha224 ();
568 md_type
= EVP_sha256 ();
571 md_type
= EVP_sha384 ();
574 md_type
= EVP_sha512 ();
577 throw new PDNSException ( "Unknown hash algorithm requested from calculateHMAC()" );
580 unsigned char * out
= HMAC ( md_type
, reinterpret_cast < const unsigned char *>( key
. c_str ()), key
. size (), reinterpret_cast < const unsigned char *>( text
. c_str ()), text
. size (), hash
, & outlen
);
581 if ( out
!= NULL
&& outlen
> 0 ) {
582 return string (( char *) hash
, outlen
);
588 string
makeTSIGMessageFromTSIGPacket ( const string
& opacket
, unsigned int tsigOffset
, const DNSName
& keyname
, const TSIGRecordContent
& trc
, const string
& previous
, bool timersonly
, unsigned int dnsHeaderOffset
)
591 string
packet ( opacket
);
593 packet
. resize ( tsigOffset
); // remove the TSIG record at the end as per RFC2845 3.4.1
594 packet
[( dnsHeaderOffset
+ sizeof ( struct dnsheader
))- 1 ]--; // Decrease ARCOUNT because we removed the TSIG RR in the previous line.
597 // Replace the message ID with the original message ID from the TSIG record.
598 // This is needed for forwarded DNS Update as they get a new ID when forwarding (section 6.1 of RFC2136). The TSIG record stores the original ID and the
599 // signature was created with the original ID, so we replace it here to get the originally signed message.
600 // If the message is not forwarded, we simply override it with the same id.
601 uint16_t origID
= htons ( trc
. d_origID
);
602 packet
. replace ( 0 , 2 , ( char *)& origID
, 2 );
604 if (! previous
. empty ()) {
605 uint16_t len
= htons ( previous
. length ());
606 message
. append (( char *)& len
, 2 );
607 message
. append ( previous
);
610 message
. append ( packet
);
612 vector
< uint8_t > signVect
;
613 DNSPacketWriter
dw ( signVect
, DNSName (), 0 );
615 dw
. xfrName ( keyname
, false );
616 dw
. xfr16BitInt ( QClass :: ANY
); // class
617 dw
. xfr32BitInt ( 0 ); // TTL
618 // dw.xfrName(toLower(trc.d_algoName), false); //FIXME400
619 dw
. xfrName ( trc
. d_algoName
, false );
622 uint32_t now
= trc
. d_time
;
624 dw
. xfr16BitInt ( trc
. d_fudge
); // fudge
626 dw
. xfr16BitInt ( trc
. d_eRcode
); // extended rcode
627 dw
. xfr16BitInt ( trc
. d_otherData
. length ()); // length of 'other' data
628 // dw.xfrBlob(trc->d_otherData);
630 const vector
< uint8_t >& signRecord
= dw
. getRecordBeingWritten ();
631 message
. append ( signRecord
. begin (), signRecord
. end ());
635 void addTSIG ( DNSPacketWriter
& pw
, TSIGRecordContent
* trc
, const DNSName
& tsigkeyname
, const string
& tsigsecret
, const string
& tsigprevious
, bool timersonly
)
638 if (! getTSIGHashEnum ( trc
-> d_algoName
, algo
)) {
639 throw PDNSException ( string ( "Unsupported TSIG HMAC algorithm " ) + trc
-> d_algoName
. toString ());
643 if (! tsigprevious
. empty ()) {
644 uint16_t len
= htons ( tsigprevious
. length ());
645 toSign
. append (( char *)& len
, 2 );
647 toSign
. append ( tsigprevious
);
649 toSign
. append ( pw
. getContent (). begin (), pw
. getContent (). end ());
651 // now add something that looks a lot like a TSIG record, but isn't
652 vector
< uint8_t > signVect
;
653 DNSPacketWriter
dw ( signVect
, DNSName (), 0 );
655 dw
. xfrName ( tsigkeyname
, false );
656 dw
. xfr16BitInt ( QClass :: ANY
); // class
657 dw
. xfr32BitInt ( 0 ); // TTL
658 dw
. xfrName ( trc
-> d_algoName
, false );
660 uint32_t now
= trc
-> d_time
;
662 dw
. xfr16BitInt ( trc
-> d_fudge
); // fudge
665 dw
. xfr16BitInt ( trc
-> d_eRcode
); // extended rcode
666 dw
. xfr16BitInt ( trc
-> d_otherData
. length ()); // length of 'other' data
667 // dw.xfrBlob(trc->d_otherData);
670 const vector
< uint8_t >& signRecord
= dw
. getRecordBeingWritten ();
671 toSign
. append ( signRecord
. begin (), signRecord
. end ());
673 if ( algo
== TSIG_GSS
) {
674 if (! gss_add_signature ( tsigkeyname
, toSign
, trc
-> d_mac
)) {
675 throw PDNSException ( string ( "Could not add TSIG signature with algorithm 'gss-tsig' and key name '" )+ tsigkeyname
. toString ()+ string ( "'" ));
678 trc
-> d_mac
= calculateHMAC ( tsigsecret
, toSign
, algo
);
679 // d_trc->d_mac[0]++; // sabotage
681 pw
. startRecord ( tsigkeyname
, QType :: TSIG
, 0 , QClass :: ANY
, DNSResourceRecord :: ADDITIONAL
, false );