"Fossies" - the Fresh Open Source Software Archive

Member "knot-2.8.3/src/knot/dnssec/rrset-sign.c" (16 Jul 2019, 11217 Bytes) of package /linux/misc/dns/knot-2.8.3.tar.xz:


As a special service "Fossies" has tried to format the requested source page into HTML format using (guessed) C and C++ source code syntax highlighting (style: standard) with prefixed line numbers and code folding option. Alternatively you can here view or download the uninterpreted source code file. For more information about "rrset-sign.c" see the Fossies "Dox" file reference documentation and the last Fossies "Diffs" side-by-side code changes report: 2.7.6_vs_2.8.0.

    1 /*  Copyright (C) 2019 CZ.NIC, z.s.p.o. <knot-dns@labs.nic.cz>
    2 
    3     This program is free software: you can redistribute it and/or modify
    4     it under the terms of the GNU General Public License as published by
    5     the Free Software Foundation, either version 3 of the License, or
    6     (at your option) any later version.
    7 
    8     This program is distributed in the hope that it will be useful,
    9     but WITHOUT ANY WARRANTY; without even the implied warranty of
   10     MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
   11     GNU General Public License for more details.
   12 
   13     You should have received a copy of the GNU General Public License
   14     along with this program.  If not, see <https://www.gnu.org/licenses/>.
   15  */
   16 
   17 #include <assert.h>
   18 
   19 #include "contrib/wire_ctx.h"
   20 #include "libdnssec/error.h"
   21 #include "knot/dnssec/rrset-sign.h"
   22 #include "knot/dnssec/zone-sign.h"
   23 #include "libknot/libknot.h"
   24 
   25 #define RRSIG_RDATA_SIGNER_OFFSET 18
   26 
   27 #define RRSIG_INCEPT_IN_PAST (90 * 60)
   28 
   29 /*- Creating of RRSIGs -------------------------------------------------------*/
   30 
   31 /*!
   32  * \brief Get size of RRSIG RDATA for a given key without signature.
   33  */
   34 static size_t rrsig_rdata_header_size(const dnssec_key_t *key)
   35 {
   36     if (!key) {
   37         return 0;
   38     }
   39 
   40     size_t size;
   41 
   42     // static part
   43 
   44     size = sizeof(uint16_t)     // type covered
   45          + sizeof(uint8_t)      // algorithm
   46          + sizeof(uint8_t)      // labels
   47          + sizeof(uint32_t)     // original TTL
   48          + sizeof(uint32_t)     // signature expiration
   49          + sizeof(uint32_t)     // signature inception
   50          + sizeof(uint16_t);    // key tag (footprint)
   51 
   52     assert(size == RRSIG_RDATA_SIGNER_OFFSET);
   53 
   54     // variable part
   55 
   56     size += knot_dname_size(dnssec_key_get_dname(key));
   57 
   58     return size;
   59 }
   60 
   61 /*!
   62  * \brief Write RRSIG RDATA except signature.
   63  *
   64  * \note This can be also used for SIG(0) if proper parameters are supplied.
   65  *
   66  * \param rdata_len     Length of RDATA.
   67  * \param rdata         Pointer to RDATA.
   68  * \param key           Key used for signing.
   69  * \param covered_type  Type of the covered RR.
   70  * \param owner_labels  Number of labels covered by the signature.
   71  * \param sig_incepted  Timestamp of signature inception.
   72  * \param sig_expires   Timestamp of signature expiration.
   73  */
   74 static int rrsig_write_rdata(uint8_t *rdata, size_t rdata_len,
   75                              const dnssec_key_t *key,
   76                              uint16_t covered_type, uint8_t owner_labels,
   77                              uint32_t owner_ttl,  uint32_t sig_incepted,
   78                              uint32_t sig_expires)
   79 {
   80     if (!rdata || !key || sig_incepted >= sig_expires) {
   81         return KNOT_EINVAL;
   82     }
   83 
   84     uint8_t algorithm = dnssec_key_get_algorithm(key);
   85     uint16_t keytag = dnssec_key_get_keytag(key);
   86     const uint8_t *signer = dnssec_key_get_dname(key);
   87     assert(signer);
   88 
   89     wire_ctx_t wire = wire_ctx_init(rdata, rdata_len);
   90 
   91     wire_ctx_write_u16(&wire, covered_type);    // type covered
   92     wire_ctx_write_u8(&wire, algorithm);        // algorithm
   93     wire_ctx_write_u8(&wire, owner_labels); // labels
   94     wire_ctx_write_u32(&wire, owner_ttl);       // original TTL
   95     wire_ctx_write_u32(&wire, sig_expires); // signature expiration
   96     wire_ctx_write_u32(&wire, sig_incepted);    // signature inception
   97     wire_ctx_write_u16(&wire, keytag);      // key fingerprint
   98     assert(wire_ctx_offset(&wire) == RRSIG_RDATA_SIGNER_OFFSET);
   99     wire_ctx_write(&wire, signer, knot_dname_size(signer)); // signer
  100 
  101     return wire.error;
  102 }
  103 
  104 /*- Computation of signatures ------------------------------------------------*/
  105 
  106 /*!
  107  * \brief Add RRSIG RDATA without signature to signing context.
  108  *
  109  * Requires signer name in RDATA in canonical form.
  110  *
  111  * \param ctx   Signing context.
  112  * \param rdata Pointer to RRSIG RDATA.
  113  *
  114  * \return Error code, KNOT_EOK if successful.
  115  */
  116 static int sign_ctx_add_self(dnssec_sign_ctx_t *ctx, const uint8_t *rdata)
  117 {
  118     assert(ctx);
  119     assert(rdata);
  120 
  121     int result;
  122 
  123     // static header
  124 
  125     dnssec_binary_t header = { 0 };
  126     header.data = (uint8_t *)rdata;
  127     header.size = RRSIG_RDATA_SIGNER_OFFSET;
  128 
  129     result = dnssec_sign_add(ctx, &header);
  130     if (result != DNSSEC_EOK) {
  131         return result;
  132     }
  133 
  134     // signer name
  135 
  136     const uint8_t *rdata_signer = rdata + RRSIG_RDATA_SIGNER_OFFSET;
  137     dnssec_binary_t signer = { 0 };
  138     signer.data = knot_dname_copy(rdata_signer, NULL);
  139     signer.size = knot_dname_size(signer.data);
  140 
  141     result = dnssec_sign_add(ctx, &signer);
  142     free(signer.data);
  143 
  144     return result;
  145 }
  146 
  147 /*!
  148  * \brief Add covered RRs to signing context.
  149  *
  150  * Requires all DNAMEs in canonical form and all RRs ordered canonically.
  151  *
  152  * \param ctx      Signing context.
  153  * \param covered  Covered RRs.
  154  *
  155  * \return Error code, KNOT_EOK if successful.
  156  */
  157 static int sign_ctx_add_records(dnssec_sign_ctx_t *ctx, const knot_rrset_t *covered)
  158 {
  159     // huge block of rrsets can be optionally created
  160     uint8_t *rrwf = malloc(KNOT_WIRE_MAX_PKTSIZE);
  161     if (!rrwf) {
  162         return KNOT_ENOMEM;
  163     }
  164 
  165     int written = knot_rrset_to_wire(covered, rrwf, KNOT_WIRE_MAX_PKTSIZE, NULL);
  166     if (written < 0) {
  167         free(rrwf);
  168         return written;
  169     }
  170 
  171     dnssec_binary_t rrset_wire = { 0 };
  172     rrset_wire.size = written;
  173     rrset_wire.data = rrwf;
  174     int result = dnssec_sign_add(ctx, &rrset_wire);
  175     free(rrwf);
  176 
  177     return result;
  178 }
  179 
  180 int knot_sign_ctx_add_data(dnssec_sign_ctx_t *ctx,
  181                            const uint8_t *rrsig_rdata,
  182                            const knot_rrset_t *covered)
  183 {
  184     if (!ctx || !rrsig_rdata || knot_rrset_empty(covered)) {
  185         return KNOT_EINVAL;
  186     }
  187 
  188     int result = sign_ctx_add_self(ctx, rrsig_rdata);
  189     if (result != KNOT_EOK) {
  190         return result;
  191     }
  192 
  193     return sign_ctx_add_records(ctx, covered);
  194 }
  195 
  196 /*!
  197  * \brief Create RRSIG RDATA.
  198  *
  199  * \param[in]  rrsigs        RR set with RRSIGS.
  200  * \param[in]  ctx           DNSSEC signing context.
  201  * \param[in]  covered       RR covered by the signature.
  202  * \param[in]  key           Key used for signing.
  203  * \param[in]  sig_incepted  Timestamp of signature inception.
  204  * \param[in]  sig_expires   Timestamp of signature expiration.
  205  *
  206  * \return Error code, KNOT_EOK if successful.
  207  */
  208 static int rrsigs_create_rdata(knot_rrset_t *rrsigs, dnssec_sign_ctx_t *ctx,
  209                                const knot_rrset_t *covered,
  210                                const dnssec_key_t *key,
  211                                uint32_t sig_incepted, uint32_t sig_expires,
  212                                knot_mm_t *mm)
  213 {
  214     assert(rrsigs);
  215     assert(rrsigs->type == KNOT_RRTYPE_RRSIG);
  216     assert(!knot_rrset_empty(covered));
  217     assert(key);
  218 
  219     size_t header_size = rrsig_rdata_header_size(key);
  220     assert(header_size != 0);
  221 
  222     uint8_t owner_labels = knot_dname_labels(covered->owner, NULL);
  223     if (knot_dname_is_wildcard(covered->owner)) {
  224         owner_labels -= 1;
  225     }
  226 
  227     uint8_t header[header_size];
  228     int res = rrsig_write_rdata(header, header_size,
  229                                 key, covered->type, owner_labels,
  230                                 covered->ttl, sig_incepted, sig_expires);
  231     assert(res == KNOT_EOK);
  232 
  233     res = dnssec_sign_init(ctx);
  234     if (res != KNOT_EOK) {
  235         return res;
  236     }
  237 
  238     res = knot_sign_ctx_add_data(ctx, header, covered);
  239     if (res != KNOT_EOK) {
  240         return res;
  241     }
  242 
  243     dnssec_binary_t signature = { 0 };
  244     res = dnssec_sign_write(ctx, &signature);
  245     if (res != DNSSEC_EOK) {
  246         return res;
  247     }
  248     assert(signature.size > 0);
  249 
  250     size_t rrsig_size = header_size + signature.size;
  251     uint8_t rrsig[rrsig_size];
  252     memcpy(rrsig, header, header_size);
  253     memcpy(rrsig + header_size, signature.data, signature.size);
  254 
  255     dnssec_binary_free(&signature);
  256 
  257     return knot_rrset_add_rdata(rrsigs, rrsig, rrsig_size, mm);
  258 }
  259 
  260 int knot_sign_rrset(knot_rrset_t *rrsigs, const knot_rrset_t *covered,
  261                     const dnssec_key_t *key, dnssec_sign_ctx_t *sign_ctx,
  262                     const kdnssec_ctx_t *dnssec_ctx, knot_mm_t *mm, knot_time_t *expires)
  263 {
  264     if (knot_rrset_empty(covered) || !key || !sign_ctx || !dnssec_ctx ||
  265         rrsigs->type != KNOT_RRTYPE_RRSIG ||
  266         !knot_dname_is_equal(rrsigs->owner, covered->owner)
  267     ) {
  268         return KNOT_EINVAL;
  269     }
  270 
  271     uint32_t sig_incept = dnssec_ctx->now - RRSIG_INCEPT_IN_PAST;
  272     uint32_t sig_expire = dnssec_ctx->now + dnssec_ctx->policy->rrsig_lifetime;
  273 
  274     int ret = rrsigs_create_rdata(rrsigs, sign_ctx, covered, key, sig_incept,
  275                                   sig_expire, mm);
  276     if (ret == KNOT_EOK && expires != NULL) {
  277         *expires = knot_time_min(*expires, sig_expire);
  278     }
  279     return ret;
  280 }
  281 
  282 int knot_sign_rrset2(knot_rrset_t *rrsigs, const knot_rrset_t *rrset,
  283                      zone_sign_ctx_t *sign_ctx, knot_mm_t *mm)
  284 {
  285     if (rrsigs == NULL || rrset == NULL || sign_ctx == NULL) {
  286         return KNOT_EINVAL;
  287     }
  288 
  289     for (size_t i = 0; i < sign_ctx->count; i++) {
  290         zone_key_t *key = &sign_ctx->keys[i];
  291 
  292         if (!knot_zone_sign_use_key(key, rrset)) {
  293             continue;
  294         }
  295 
  296         int ret = knot_sign_rrset(rrsigs, rrset, key->key, sign_ctx->sign_ctxs[i],
  297                                   sign_ctx->dnssec_ctx, mm, NULL);
  298         if (ret != KNOT_EOK) {
  299             return ret;
  300         }
  301     }
  302 
  303     return KNOT_EOK;
  304 }
  305 
  306 int knot_synth_rrsig(uint16_t type, const knot_rdataset_t *rrsig_rrs,
  307                      knot_rdataset_t *out_sig, knot_mm_t *mm)
  308 {
  309     if (rrsig_rrs == NULL) {
  310         return KNOT_ENOENT;
  311     }
  312 
  313     if (out_sig == NULL || out_sig->count > 0) {
  314         return KNOT_EINVAL;
  315     }
  316 
  317     knot_rdata_t *rr_to_copy = rrsig_rrs->rdata;
  318     for (int i = 0; i < rrsig_rrs->count; ++i) {
  319         if (type == knot_rrsig_type_covered(rr_to_copy)) {
  320             int ret = knot_rdataset_add(out_sig, rr_to_copy, mm);
  321             if (ret != KNOT_EOK) {
  322                 knot_rdataset_clear(out_sig, mm);
  323                 return ret;
  324             }
  325         }
  326         rr_to_copy = knot_rdataset_next(rr_to_copy);
  327     }
  328 
  329     return out_sig->count > 0 ? KNOT_EOK : KNOT_ENOENT;
  330 }
  331 
  332 /*- Verification of signatures -----------------------------------------------*/
  333 
  334 /*!
  335  * \brief Check if the signature is expired.
  336  *
  337  * \param rrsig   RRSIG rdata.
  338  * \param policy  DNSSEC policy.
  339  *
  340  * \return Signature is expired or should be replaced soon.
  341  */
  342 static bool is_expired_signature(const knot_rdata_t *rrsig, uint32_t now,
  343                                  uint32_t refresh_before)
  344 {
  345     assert(rrsig);
  346 
  347     uint32_t expire_at = knot_rrsig_sig_expiration(rrsig);
  348     uint32_t expire_in = expire_at > now ? expire_at - now : 0;
  349 
  350     return expire_in <= refresh_before;
  351 }
  352 
  353 int knot_check_signature(const knot_rrset_t *covered,
  354                     const knot_rrset_t *rrsigs, size_t pos,
  355                     const dnssec_key_t *key,
  356                     dnssec_sign_ctx_t *sign_ctx,
  357                     const kdnssec_ctx_t *dnssec_ctx)
  358 {
  359     if (knot_rrset_empty(covered) || knot_rrset_empty(rrsigs) || !key ||
  360         !sign_ctx || !dnssec_ctx) {
  361         return KNOT_EINVAL;
  362     }
  363 
  364     knot_rdata_t *rrsig = knot_rdataset_at(&rrsigs->rrs, pos);
  365     assert(rrsig);
  366 
  367     if (is_expired_signature(rrsig, dnssec_ctx->now,
  368                              dnssec_ctx->policy->rrsig_refresh_before)) {
  369         return DNSSEC_INVALID_SIGNATURE;
  370     }
  371 
  372     // identify fields in the signature being validated
  373 
  374     dnssec_binary_t signature = {
  375         .size = knot_rrsig_signature_len(rrsig),
  376         .data = (uint8_t *)knot_rrsig_signature(rrsig)
  377     };
  378     if (signature.data == NULL) {
  379         return KNOT_EINVAL;
  380     }
  381 
  382     // perform the validation
  383 
  384     int result = dnssec_sign_init(sign_ctx);
  385     if (result != KNOT_EOK) {
  386         return result;
  387     }
  388 
  389     result = knot_sign_ctx_add_data(sign_ctx, rrsig->data, covered);
  390     if (result != KNOT_EOK) {
  391         return result;
  392     }
  393 
  394     return dnssec_sign_verify(sign_ctx, &signature);
  395 }