3 * Copyright (c) 2018 Apple Computer, Inc. All rights reserved.
5 * Licensed under the Apache License, Version 2.0 (the "License");
6 * you may not use this file except in compliance with the License.
7 * You may obtain a copy of the License at
9 * http://www.apache.org/licenses/LICENSE-2.0
11 * Unless required by applicable law or agreed to in writing, software
12 * distributed under the License is distributed on an "AS IS" BASIS,
13 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
14 * See the License for the specific language governing permissions and
15 * limitations under the License.
17 * DNS SIG(0) signature verification for DNSSD SRP using mbedtls.
19 * Provides functions for generating a public key validating context based on SIG(0) KEY RR data, and
20 * validating a signature using a context generated with that public key. Currently only ECDSASHA256 is
25 #include <arpa/inet.h>
30 #define SRP_CRYPTO_MBEDTLS_INTERNAL
32 #include "srp-crypto.h"
35 // Given a DNS message, a signature, and a public key, validate the message
37 srp_sig0_verify(dns_wire_t
*message
, dns_rr_t
*key
, dns_rr_t
*signature
)
39 mbedtls_ecp_point pubkey
;
40 mbedtls_ecp_group group
;
41 mbedtls_sha256_context sha
;
44 uint8_t hash
[ECDSA_SHA256_HASH_SIZE
];
49 // The key algorithm and the signature algorithm have to match or we can't validate the signature.
50 if (key
->data
.key
.algorithm
!= signature
->data
.sig
.algorithm
) {
54 // Key must be the right length (DNS ECDSA KEY isn't compressed).
55 if (key
->data
.key
.len
!= ECDSA_KEY_SIZE
) {
59 // Currently only support ecdsa
60 if (signature
->data
.sig
.algorithm
!= dnssec_keytype_ecdsa
) {
64 // Make sure the signature is the right size.
65 if (signature
->data
.sig
.len
!= ECDSA_SHA256_SIG_SIZE
) {
69 // Take the KEY RR and turn it into a public key we can use to check the signature.
70 // Initialize the ECP group (SECP256).
71 mbedtls_ecp_point_init(&pubkey
);
72 mbedtls_ecp_group_init(&group
);
73 mbedtls_ecp_group_load(&group
, MBEDTLS_ECP_DP_SECP256R1
);
76 mbedtls_sha256_init(&sha
);
77 memset(hash
, 0, sizeof hash
);
79 if ((status
= mbedtls_mpi_read_binary(&pubkey
.X
, key
->data
.key
.key
, ECDSA_KEY_PART_SIZE
)) != 0 ||
80 (status
= mbedtls_mpi_read_binary(&pubkey
.Y
, key
->data
.key
.key
+ ECDSA_KEY_PART_SIZE
, ECDSA_KEY_PART_SIZE
)) != 0) {
81 mbedtls_strerror(status
, errbuf
, sizeof errbuf
);
82 ERROR("mbedtls_mpi_read_binary: reading key: " PUB_S_SRP
, errbuf
);
84 mbedtls_mpi_lset(&pubkey
.Z
, 1);
86 if ((status
= mbedtls_mpi_read_binary(&r
, signature
->data
.sig
.signature
, ECDSA_SHA256_SIG_PART_SIZE
)) != 0 ||
87 (status
= mbedtls_mpi_read_binary(&s
, signature
->data
.sig
.signature
+ ECDSA_SHA256_SIG_PART_SIZE
,
88 ECDSA_SHA256_SIG_PART_SIZE
)) != 0) {
89 mbedtls_strerror(status
, errbuf
, sizeof errbuf
);
90 ERROR("mbedtls_mpi_read_binary: reading signature: " PUB_S_SRP
, errbuf
);
93 // The hash is across the message _before_ the SIG RR is added, so we have to decrement arcount before
95 message
->arcount
= htons(ntohs(message
->arcount
) - 1);
97 // And the SIG RRDATA that we hash includes the canonical version of the name, not whatever bits
98 // are in the actual wire format message, so we have to just make a copy of it.
99 rdlen
= SIG_STATIC_RDLEN
+ dns_name_wire_length(signature
->data
.sig
.signer
);
100 rdata
= malloc(rdlen
);
102 ERROR("no memory for SIG RR canonicalization");
105 memcpy(rdata
, &message
->data
[signature
->data
.sig
.start
+ SIG_HEADERLEN
], SIG_STATIC_RDLEN
);
106 if (!dns_name_to_wire_canonical(rdata
+ SIG_STATIC_RDLEN
, rdlen
- SIG_STATIC_RDLEN
,
107 signature
->data
.sig
.signer
)) {
108 // Should never happen.
109 ERROR("dns_name_wire_length and dns_name_to_wire_canonical got different lengths!");
113 // First compute the hash across the SIG RR, then hash the message up to the SIG RR
114 if ((status
= mbedtls_sha256_starts_ret(&sha
, 0)) != 0 ||
115 (status
= srp_mbedtls_sha256_update_ret("rdata", &sha
, rdata
, rdlen
)) != 0 ||
116 (status
= srp_mbedtls_sha256_update_ret("message", &sha
, (uint8_t *)message
,
117 signature
->data
.sig
.start
+
118 (sizeof *message
) - DNS_DATA_SIZE
)) != 0 ||
119 (status
= srp_mbedtls_sha256_finish_ret(&sha
, hash
)) != 0) {
121 message
->arcount
= htons(ntohs(message
->arcount
) + 1);
122 mbedtls_strerror(status
, errbuf
, sizeof errbuf
);
123 ERROR("mbedtls_sha_256 hash failed: " PUB_S_SRP
, errbuf
);
126 message
->arcount
= htons(ntohs(message
->arcount
) + 1);
129 // Now check the signature against the hash
130 status
= mbedtls_ecdsa_verify(&group
, hash
, sizeof hash
, &pubkey
, &r
, &s
);
132 mbedtls_strerror(status
, errbuf
, sizeof errbuf
);
133 ERROR("mbedtls_ecdsa_verify failed: " PUB_S_SRP
, errbuf
);
139 // Function to copy out the public key as binary data
141 srp_print_key(srp_key_t
*key
)
143 mbedtls_ecp_keypair
*ecp
= mbedtls_pk_ec(key
->key
);
145 uint8_t buf
[ECDSA_KEY_SIZE
];
146 uint8_t b64buf
[((ECDSA_KEY_SIZE
* 4) / 3) + 6];
150 // Currently ECP only.
151 if ((status
= mbedtls_mpi_write_binary(&ecp
->Q
.X
, buf
, ECDSA_KEY_PART_SIZE
)) != 0 ||
152 (status
= mbedtls_mpi_write_binary(&ecp
->Q
.Y
, buf
+ ECDSA_KEY_PART_SIZE
, ECDSA_KEY_PART_SIZE
)) != 0) {
153 mbedtls_strerror(status
, errbuf
, sizeof errbuf
);
154 ERROR("mbedtls_mpi_write_binary: " PUB_S_SRP
, errbuf
);
158 status
= mbedtls_base64_encode(b64buf
, sizeof b64buf
, &b64len
, buf
, ECDSA_KEY_SIZE
);
160 mbedtls_strerror(status
, errbuf
, sizeof errbuf
);
161 ERROR("mbedtls_mpi_write_binary: " PUB_S_SRP
, errbuf
);
164 fputs("thread-demo.default.service.arpa. IN KEY 513 3 13 ", stdout
);
165 fwrite(b64buf
, b64len
, 1, stdout
);
172 // c-file-style: "bsd"
175 // indent-tabs-mode: nil