| 
					
				 | 
			
			
				@@ -0,0 +1,130 @@ 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+/* Copyright 2004 Roger Dingledine */ 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+/* See LICENSE for licensing information */ 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+/* $Id$ */ 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+ 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+#include "or.h" 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+ 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+void rend_service_descriptor_free(rend_service_descriptor_t *desc) 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+{ 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+  int i; 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+  if (desc->pk) 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+    crypto_free_pk_env(desc->pk); 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+  if (desc->intro_points) { 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+    for (i=0; i < desc->n_intro_points; ++i) { 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+      tor_free(desc->intro_points[i]); 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+    } 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+    tor_free(desc->intro_points); 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+  } 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+  tor_free(desc); 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+} 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+ 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+int 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+rend_encode_service_descriptor(rend_service_descriptor_t *desc, 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+			       crypto_pk_env_t *key, 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+			       char **str_out, int *len_out) 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+{ 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+  char *buf, *cp, *ipoint; 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+  int i, keylen, asn1len; 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+  char digest[CRYPTO_SHA1_DIGEST_LEN]; 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+  keylen = crypto_pk_keysize(desc->pk); 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+  buf = tor_malloc(keylen*2); /* XXXX */ 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+  asn1len = crypto_pk_asn1_encode(desc->pk, buf, keylen*2); 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+  if (asn1len<0) { 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+    tor_free(buf); 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+    return -1; 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+  } 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+  *len_out = 2 + asn1len + 4 + 2 + keylen; 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+  for (i = 0; i < desc->n_intro_points; ++i) { 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+    *len_out += strlen(desc->intro_points[i]) + 1; 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+  } 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+  cp = *str_out = tor_malloc(*len_out); 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+  set_uint16(cp, (uint16_t)asn1len); 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+  cp += 2; 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+  memcpy(cp, buf, asn1len); 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+  tor_free(buf); 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+  cp += asn1len; 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+  set_uint32(cp, (uint32_t)desc->timestamp); 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+  cp += 4; 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+  set_uint16(cp, (uint16_t)desc->n_intro_points); 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+  cp += 2; 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+  for (i=0; i < desc->n_intro_points; ++i) { 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+    ipoint = (char*)desc->intro_points[i]; 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+    strcpy(cp, ipoint); 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+    cp += strlen(ipoint)+1; 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+  } 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+  i = crypto_SHA_digest(*str_out, cp-*str_out, digest); 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+  if (i<0) { 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+    tor_free(*str_out); 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+    return -1; 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+  } 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+  i = crypto_pk_private_sign(key, digest, CRYPTO_SHA1_DIGEST_LEN, cp); 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+  if (i<0) { 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+    tor_free(*str_out); 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+    return -1; 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+  } 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+  cp += i; 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+  assert(*len_out == (cp-*str_out)); 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+  return 0; 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+} 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+ 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+ 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+rend_service_descriptor_t *rend_parse_service_descriptor( 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+				       const char *str, int len) 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+{ 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+  rend_service_descriptor_t *result = NULL; 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+  int keylen, asn1len, i; 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+  const char *end, *cp, *eos; 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+  char *signed_data=NULL; 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+  char digest_expected[CRYPTO_SHA1_DIGEST_LEN]; 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+  result = tor_malloc_zero(sizeof(rend_service_descriptor_t)); 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+  cp = str; 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+  end = str+len; 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+  if (end-cp < 2) goto truncated; 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+  asn1len = get_uint16(cp); 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+  cp += 2; 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+  if (end-cp < asn1len) goto truncated; 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+  result->pk = crypto_pk_asn1_decode(cp, asn1len); 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+  if (!result->pk) goto truncated; 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+  cp += asn1len; 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+  if (end-cp < 4) goto truncated; 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+  result->timestamp = (time_t) get_uint32(cp); 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+  cp += 4; 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+  if (end-cp < 2) goto truncated; 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+  result->n_intro_points = get_uint16(cp); 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+  result->intro_points = tor_malloc_zero(sizeof(char*)*result->n_intro_points); 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+  cp += 2; 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+  for (i=0;i<result->n_intro_points;++i) { 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+    if (end-cp < 2) goto truncated; 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+    eos = (const char *)memchr(cp,'\0',end-cp); 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+    if (!eos) goto truncated; 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+    result->intro_points[i] = tor_strdup(cp); 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+    cp = eos+1; 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+  } 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+  keylen = crypto_pk_keysize(result->pk); 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+  if (end-cp != keylen) goto truncated; 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+  if (crypto_SHA_digest(str, cp-str, digest_expected)<0) { 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+    log_fn(LOG_WARN, "Error computing SHA1 digest."); 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+    goto error; 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+  } 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+  signed_data = tor_malloc(keylen+1); 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+  i = crypto_pk_public_checksig(result->pk, (char*)cp, end-cp, signed_data); 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+  if (i<0) { 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+    log_fn(LOG_WARN, "Invalid signature on service descriptor"); 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+    goto error; 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+  } 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+  if (i != CRYPTO_SHA1_DIGEST_LEN || 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+      memcmp(signed_data, digest_expected, CRYPTO_SHA1_DIGEST_LEN)) { 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+    log_fn(LOG_WARN, "Mismatched signature on service descriptor"); 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+    goto error; 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+  } 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+  tor_free(signed_data); 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+ 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+  return result; 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+ truncated: 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+  log_fn(LOG_WARN, "Truncated service descriptor"); 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+ error: 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+  tor_free(signed_data); 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+  rend_service_descriptor_free(result); 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+  return NULL; 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+} 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+ 
			 |