diff --git a/src/pubkey-pinning.c b/src/pubkey-pinning.c index fba25d7c..96d37fe1 100644 --- a/src/pubkey-pinning.c +++ b/src/pubkey-pinning.c @@ -50,6 +50,7 @@ #include #include #include +#include "context.h" /* we only support sha256 at the moment. adding support for another digest is more complex than just adding another entry here. in @@ -212,4 +213,100 @@ getdns_return_t getdns_pubkey_pinset_sanity_check( return GETDNS_RETURN_GENERIC_ERROR; return GETDNS_RETURN_GOOD; } + +getdns_return_t +_getdns_get_pubkey_pinset_from_list(const getdns_list *pinset_list, + struct mem_funcs *mf, + sha256_pin_t **pinset_out) +{ + getdns_return_t r; + size_t pins, i; + sha256_pin_t *out = NULL, *onext = NULL; + getdns_dict * pin; + getdns_bindata * data = NULL; + + if (r = getdns_list_get_length(pinset_list, &pins), r) + return r; + for (i = 0; i < pins; i++) + { + if (r = getdns_list_get_dict(pinset_list, i, &pin), r) + goto fail; + /* does the pin have the right digest type? */ + if (r = getdns_dict_get_bindata(pin, "digest", &data), r) + goto fail; + if (data->size != sha256.size || + memcmp(data->data, sha256.data, sha256.size)) { + r = GETDNS_RETURN_INVALID_PARAMETER; + goto fail; + } + /* if it does, is the value the right length? */ + if (r = getdns_dict_get_bindata(pin, "value", &data), r) + goto fail; + if (data->size != SHA256_DIGEST_LENGTH) { + r = GETDNS_RETURN_INVALID_PARAMETER; + goto fail; + } + /* make a new pin */ + onext = GETDNS_MALLOC(*mf, sha256_pin_t); + if (onext == NULL) { + r = GETDNS_RETURN_MEMORY_ERROR; + goto fail; + } + onext->next = out; + memcpy(onext->pin, data->data, SHA256_DIGEST_LENGTH); + out = onext; + } + + *pinset_out = out; + return GETDNS_RETURN_GOOD; + fail: + while (out) { + onext = out->next; + GETDNS_FREE(*mf, out); + out = onext; + } + return r; +} + +getdns_return_t +_getdns_get_pubkey_pinset_list(getdns_context *ctx, + const sha256_pin_t *pinset_in, + getdns_list **pinset_list) +{ + getdns_list *out = getdns_list_create_with_context(ctx); + getdns_return_t r; + uint8_t buf[SHA256_DIGEST_LENGTH]; + getdns_bindata value = { .size = SHA256_DIGEST_LENGTH, .data = buf }; + getdns_dict *pin = NULL; + size_t idx = 0; + + if (out == NULL) + return GETDNS_RETURN_MEMORY_ERROR; + while (pinset_in) { + pin = getdns_dict_create_with_context(ctx); + if (pin == NULL) { + r = GETDNS_RETURN_MEMORY_ERROR; + goto fail; + } + if (r = getdns_dict_set_bindata(pin, "digest", &sha256), r) + goto fail; + memcpy(buf, pinset_in->pin, sizeof(buf)); + if (r = getdns_dict_set_bindata(pin, "value", &value), r) + goto fail; + if (r = getdns_list_set_dict(out, idx++, pin), r) + goto fail; + getdns_dict_destroy(pin); + pin = NULL; + pinset_in = pinset_in->next; + } + + *pinset_list = out; + return GETDNS_RETURN_GOOD; + fail: + getdns_dict_destroy(pin); + getdns_list_destroy(out); + return r; +} + + /* pubkey-pinning.c */ diff --git a/src/pubkey-pinning.h b/src/pubkey-pinning.h new file mode 100644 index 00000000..3b5a5983 --- /dev/null +++ b/src/pubkey-pinning.h @@ -0,0 +1,53 @@ +/** + * + * /brief internal functions for dealing with pubkey pinsets + * + */ + +/* + * Copyright (c) 2015 ACLU + * All rights reserved. + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions are met: + * * Redistributions of source code must retain the above copyright + * notice, this list of conditions and the following disclaimer. + * * Redistributions in binary form must reproduce the above copyright + * notice, this list of conditions and the following disclaimer in the + * documentation and/or other materials provided with the distribution. + * * Neither the names of the copyright holders nor the + * names of its contributors may be used to endorse or promote products + * derived from this software without specific prior written permission. + * + * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" AND + * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED + * WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE + * DISCLAIMED. IN NO EVENT SHALL Verisign, Inc. BE LIABLE FOR ANY + * DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES + * (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; + * LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND + * ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT + * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS + * SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. + */ + +#ifndef PUBKEY_PINNING_H_ +#define PUBKEY_PINNING_H_ + + +/* create and populate a pinset linked list from a getdns_list pinset */ +getdns_return_t +_getdns_get_pubkey_pinset_from_list(const getdns_list *pinset_list, + struct mem_funcs *mf, + sha256_pin_t **pinset_out); + + +/* create a getdns_list version of the pinset */ +getdns_return_t +_getdns_get_pubkey_pinset_list(getdns_context *ctx, + const sha256_pin_t *pinset_in, + getdns_list **pinset_list); + + +#endif +/* pubkey-pinning.h */