+/* if trustpolicy is 0, we just accept anything */
+int verify_trust(struct TLSContext *context, struct TLSCertificate **chain, int
+ len) {
+ /* suppress unused */
+ if (context || chain || len) {
+ return 0;
+ }
+
+ return 0;
+}
+
+static char hexchars[] = "0123456789abcdefABCDEF";
+
+static void hex(char *dst, uint8_t *src, size_t len) {
+ while (len--) {
+ dst[0] = hexchars[(src[0]>>4)&0xf];
+ dst[1] = hexchars[src[0]&0xf];
+ dst+=2;
+ src++;
+ }
+}
+
+#if 0
+static void hexbin(uint8_t *dst, unsigned char *src, size_t len) {
+ size_t i;
+ int x;
+
+ for (i=0; i<len; i+=2) {
+ sscanf((const char *)src+i, "%02x", &x);
+ dst[i/2] = x;
+ }
+}
+#endif
+
+char *my_getline(struct tls_buffer *b, int fd, size_t *size) {
+ char *loc = 0;
+ char buf[4096];
+ ssize_t rv = 0;
+
+ while (b->error == 0) {
+ loc = memchr(b->buffer, '\n', b->len);
+ if (loc) {
+ *size = loc - b->buffer + 1;
+ return b->buffer;
+ } else {
+ rv = read(fd, buf, sizeof buf);
+ if (rv == -1) {
+ return 0;
+ }
+ if (rv == 0) {
+ break;
+ }
+ tls_buffer_append(b, buf, rv);
+ }
+ }
+ if (rv == 0) {
+ *size = b->len;
+ return b->buffer;
+ }
+ return 0;
+}
+
+/*
+ * We use a trust on first use policy. The trust DB is a simple
+ * file in /var/lib/zpm/known_hosts, or ~/.zpm/known_hosts, or ZPM_KNOWNHOSTS.
+ * if -k is given, no verification is done
+ */
+int verify_first(struct TLSContext *context, struct TLSCertificate **chain, int
+ certs) {
+ int err;
+ char *trustfile, *homedir = 0, *host, *fp;
+ unsigned char certhash[65];
+ int trustdb;
+ struct tls_buffer tbuf;
+
+ char *line = 0;
+ size_t len = 0;
+
+ if (certs == 0 || chain == 0) {
+ return 1;
+ }
+
+ err = tls_certificate_is_valid(chain[0]);
+ if (err) {
+ return err;
+ }
+
+ if (context->sni) {
+ err = tls_certificate_valid_subject(chain[0], context->sni);
+ if (err) {
+ return err;
+ }
+ }
+
+ hex(certhash, chain[0]->fp, 32);
+ certhash[64] = 0;
+
+ trustfile = getenv("ZPM_KNOWNHOSTS");
+ if (!trustfile) {
+ if (geteuid() == 0) {
+ trustfile = "/var/lib/zpm/known_hosts";
+ } else {
+ homedir = getenv("HOME");
+ if (!homedir) {
+ return 1;
+ }
+ len = snprintf(homedir, 0, "%s/.zpm/known_hosts", homedir);
+ homedir = malloc(len+1);
+ if (!homedir) {
+ return 1;
+ }
+ len = snprintf(homedir, len+1, "%s/.zpm/known_hosts", homedir);
+ trustfile = homedir;
+ }
+ }
+ /* cert is valid on its face, so check against the trust db */
+ trustdb = open(trustfile, O_RDWR|O_CREAT, 0600);
+ if (homedir) {
+ free(homedir);
+ }
+ if (trustdb == -1) {
+ fprintf(stderr, "cannot open trustdb: %s\n", strerror(errno));
+ return 1;
+ }
+
+ len = 0;
+ tls_buffer_init(&tbuf, 128);
+ do {
+ char *off;
+
+ tls_buffer_shift(&tbuf, len);
+ line = my_getline(&tbuf, trustdb, &len);
+
+ if (!line || !len) {
+ break;
+ }
+
+ fp = line;
+ while (isspace(*fp)) {
+ fp++;
+ }
+ if (*fp == '#') {
+ continue;
+ }
+ off = strchr(line, ':');
+ if (!off) {
+ continue;
+ }
+ host = off + 1;
+ *off = 0;
+ if (line[len-1] == '\n') {
+ line[len-1] = 0;
+ }
+
+ if (strlen(fp) != 64) {
+ continue;
+ }
+
+ if (len && line[len-1] == '\n') {
+ line[len-1] = 0;
+ }
+
+ if (strcmp(context->sni, host) != 0) {
+ continue;
+ }
+
+ int match = (memcmp(certhash, fp, 64) == 0);
+
+ close(trustdb);
+ tls_buffer_free(&tbuf);
+ return match ? no_error : bad_certificate;
+ } while (!tbuf.error);
+
+ /* got here, so we should be at EOF, so add this host to trust db */
+ lseek(trustdb, 0, SEEK_END);
+ write(trustdb, certhash, 64);
+ write(trustdb, ":", 1);
+ write(trustdb, context->sni, strlen(context->sni));
+ write(trustdb, "\n", 1);
+ close(trustdb);
+ tls_buffer_free(&tbuf);
+
+ return no_error;
+}
+
+int verify_roots(struct TLSContext *context, struct TLSCertificate **chain, int
+ len) {