/* convert an HPKP-style pin description to an appropriate getdns data structure. An example string is: (with the quotes, without any leading or trailing whitespace): pin-sha256="E9CZ9INDbd+2eRQozYqqbQ2yXLVKB9+xcprMF+44U1g=" getdns_build_pin_from_string returns a dict created from ctx, or NULL if the string did not match. If ctx is NULL, the dict is created via getdns_dict_create(). It is the caller's responsibility to call getdns_dict_destroy when it is no longer needed. */ getdns_dict* getdns_pubkey_pin_create_from_string( getdns_context* context, const char* str) { BIO *bio = NULL; int i; uint8_t buf[SHA256_DIGEST_LENGTH]; char inbuf[B64_ENCODED_SHA256_LENGTH + 1]; getdns_bindata value = { .size = SHA256_DIGEST_LENGTH, .data = buf }; getdns_dict* out = NULL; /* we only do sha256 right now, make sure this is well-formed */ if (strncmp(PIN_PREFIX, str, PIN_PREFIX_LENGTH)) return NULL; for (i = PIN_PREFIX_LENGTH; i < PIN_PREFIX_LENGTH + B64_ENCODED_SHA256_LENGTH - 1; i++) if (!((str[i] >= 'a' && str[i] <= 'z') || (str[i] >= 'A' && str[i] <= 'Z') || (str[i] >= '0' && str[i] <= '9') || (str[i] == '+') || (str[i] == '/'))) return NULL; if (str[i++] != '=') return NULL; if (str[i++] != '"') return NULL; if (str[i++] != '\0') return NULL; /* openssl needs a trailing newline to base64 decode */ memcpy(inbuf, str + PIN_PREFIX_LENGTH, B64_ENCODED_SHA256_LENGTH); inbuf[B64_ENCODED_SHA256_LENGTH] = '\n'; bio = BIO_push(BIO_new(BIO_f_base64()), BIO_new_mem_buf(inbuf, sizeof(inbuf))); if (BIO_read(bio, buf, sizeof(buf)) != sizeof(buf)) goto fail; if (context) out = getdns_dict_create_with_context(context); else out = getdns_dict_create(); if (out == NULL) goto fail; if (getdns_dict_set_bindata(out, "digest", &sha256)) goto fail; if (getdns_dict_set_bindata(out, "value", &value)) goto fail; return out; fail: BIO_free_all(bio); getdns_dict_destroy(out); return NULL; }
getdns_dict * ipaddr_dict(getdns_context *context, char *ipstr) { getdns_dict *r = getdns_dict_create_with_context(context); char *s = strchr(ipstr, '%'), *scope_id_str = ""; char *p = strchr(ipstr, '@'), *portstr = ""; char *t = strchr(ipstr, '#'), *tls_portstr = ""; uint8_t buf[sizeof(struct in6_addr)]; getdns_bindata addr; addr.data = buf; if (!r) return NULL; if (s) { *s = 0; scope_id_str = s + 1; } if (p) { *p = 0; portstr = p + 1; } if (t) { *t = 0; tls_portstr = t + 1; } if (strchr(ipstr, ':')) { getdns_dict_util_set_string(r, "address_type", "IPv6"); addr.size = 16; if (inet_pton(AF_INET6, ipstr, buf) <= 0) { getdns_dict_destroy(r); return NULL; } } else { getdns_dict_util_set_string(r, "address_type", "IPv4"); addr.size = 4; if (inet_pton(AF_INET, ipstr, buf) <= 0) { getdns_dict_destroy(r); return NULL; } } getdns_dict_set_bindata(r, "address_data", &addr); if (*portstr) getdns_dict_set_int(r, "port", (int32_t)atoi(portstr)); if (*tls_portstr) getdns_dict_set_int(r, "tls_port", (int32_t)atoi(tls_portstr)); if (*scope_id_str) getdns_dict_util_set_string(r, "scope_id", scope_id_str); return r; }
/* convert an HPKP-style pin description to an appropriate getdns data structure. An example string is: (with the quotes, without any leading or trailing whitespace): pin-sha256="E9CZ9INDbd+2eRQozYqqbQ2yXLVKB9+xcprMF+44U1g=" getdns_build_pin_from_string returns a dict created from ctx, or NULL if the string did not match. If ctx is NULL, the dict is created via getdns_dict_create(). It is the caller's responsibility to call getdns_dict_destroy when it is no longer needed. */ getdns_dict *getdns_pubkey_pin_create_from_string( const getdns_context *context, const char *str) { size_t i; uint8_t buf[SHA256_DIGEST_LENGTH]; getdns_bindata value = { .size = SHA256_DIGEST_LENGTH, .data = buf }; getdns_dict *out = NULL; /* we only do sha256 right now, make sure this is well-formed */ if (!str || strncmp(PIN_PREFIX, str, PIN_PREFIX_LENGTH)) return NULL; for (i = PIN_PREFIX_LENGTH; i < PIN_PREFIX_LENGTH + B64_ENCODED_SHA256_LENGTH - 1; i++) if (!((str[i] >= 'a' && str[i] <= 'z') || (str[i] >= 'A' && str[i] <= 'Z') || (str[i] >= '0' && str[i] <= '9') || (str[i] == '+') || (str[i] == '/'))) return NULL; if (str[i++] != '=') return NULL; if (str[i++] != '"') return NULL; if (str[i++] != '\0') return NULL; if (_getdns_decode_base64(str + PIN_PREFIX_LENGTH, buf, sizeof(buf)) != GETDNS_RETURN_GOOD) goto fail; if (context) out = getdns_dict_create_with_context(context); else out = getdns_dict_create(); if (out == NULL) goto fail; if (getdns_dict_set_bindata(out, "digest", &sha256)) goto fail; if (getdns_dict_set_bindata(out, "value", &value)) goto fail; return out; fail: getdns_dict_destroy(out); return NULL; }
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; }