|  | @@ -1761,3 +1761,84 @@ connection_or_send_netinfo(or_connection_t *conn)
 | 
	
		
			
				|  |  |    return 0;
 | 
	
		
			
				|  |  |  }
 | 
	
		
			
				|  |  |  
 | 
	
		
			
				|  |  | +/** DOCDOC */
 | 
	
		
			
				|  |  | +#define OR_CERT_TYPE_TLS_LINK 1
 | 
	
		
			
				|  |  | +#define OR_CERT_TYPE_ID_1024 2
 | 
	
		
			
				|  |  | +
 | 
	
		
			
				|  |  | +/** Send a CERT cell on the connection <b>conn</b>.  Return 0 on success, -1
 | 
	
		
			
				|  |  | + * on failure. */
 | 
	
		
			
				|  |  | +int
 | 
	
		
			
				|  |  | +connection_or_send_cert_cell(or_connection_t *conn)
 | 
	
		
			
				|  |  | +{
 | 
	
		
			
				|  |  | +  const tor_cert_t *link_cert = NULL, *id_cert = NULL;
 | 
	
		
			
				|  |  | +  const uint8_t *link_encoded = NULL, *id_encoded = NULL;
 | 
	
		
			
				|  |  | +  size_t link_len, id_len;
 | 
	
		
			
				|  |  | +  var_cell_t *cell;
 | 
	
		
			
				|  |  | +  size_t cell_len;
 | 
	
		
			
				|  |  | +  int pos;
 | 
	
		
			
				|  |  | +
 | 
	
		
			
				|  |  | +  tor_assert(conn->_base.state == OR_CONN_STATE_OR_HANDSHAKING_V3);
 | 
	
		
			
				|  |  | +
 | 
	
		
			
				|  |  | +  if (! conn->handshake_state)
 | 
	
		
			
				|  |  | +    return -1;
 | 
	
		
			
				|  |  | +  if (tor_tls_get_my_certs(! conn->handshake_state->started_here,
 | 
	
		
			
				|  |  | +                           &link_cert, &id_cert) < 0)
 | 
	
		
			
				|  |  | +    return -1;
 | 
	
		
			
				|  |  | +  tor_cert_get_der(link_cert, &link_encoded, &link_len);
 | 
	
		
			
				|  |  | +  tor_cert_get_der(id_cert, &id_encoded, &id_len);
 | 
	
		
			
				|  |  | +
 | 
	
		
			
				|  |  | +  cell_len = 1 /* 1 octet: num certs in cell */ +
 | 
	
		
			
				|  |  | +             2 * ( 1 + 2 ) /* For each cert: 1 octet for type, 2 for length */ +
 | 
	
		
			
				|  |  | +             link_len + id_len;
 | 
	
		
			
				|  |  | +  cell = var_cell_new(cell_len);
 | 
	
		
			
				|  |  | +  cell->command = CELL_CERT;
 | 
	
		
			
				|  |  | +  cell->payload[0] = 2;
 | 
	
		
			
				|  |  | +  pos = 1;
 | 
	
		
			
				|  |  | +
 | 
	
		
			
				|  |  | +  cell->payload[pos] = OR_CERT_TYPE_TLS_LINK; /* Link cert  */
 | 
	
		
			
				|  |  | +  set_uint16(&cell->payload[pos+1], htons(link_len));
 | 
	
		
			
				|  |  | +  memcpy(&cell->payload[pos+3], link_encoded, link_len);
 | 
	
		
			
				|  |  | +  pos += 3 + link_len;
 | 
	
		
			
				|  |  | +
 | 
	
		
			
				|  |  | +  cell->payload[pos] = OR_CERT_TYPE_ID_1024; /* ID cert */
 | 
	
		
			
				|  |  | +  set_uint16(&cell->payload[pos+1], htons(id_len));
 | 
	
		
			
				|  |  | +  memcpy(&cell->payload[pos+3], id_encoded, id_len);
 | 
	
		
			
				|  |  | +  pos += 3 + id_len;
 | 
	
		
			
				|  |  | +
 | 
	
		
			
				|  |  | +  tor_assert(pos == (int)cell_len); /* Otherwise we just smashed the heap */
 | 
	
		
			
				|  |  | +
 | 
	
		
			
				|  |  | +  connection_or_write_var_cell_to_buf(cell, conn);
 | 
	
		
			
				|  |  | +  var_cell_free(cell);
 | 
	
		
			
				|  |  | +
 | 
	
		
			
				|  |  | +  return 0;
 | 
	
		
			
				|  |  | +}
 | 
	
		
			
				|  |  | +
 | 
	
		
			
				|  |  | +/** Send an AUTH_CHALLENGE cell on the connection <b>conn</b>. Return 0
 | 
	
		
			
				|  |  | + * on success, -1 on failure. */
 | 
	
		
			
				|  |  | +int
 | 
	
		
			
				|  |  | +connection_or_send_auth_challenge_cell(or_connection_t *conn)
 | 
	
		
			
				|  |  | +{
 | 
	
		
			
				|  |  | +  var_cell_t *cell;
 | 
	
		
			
				|  |  | +  uint8_t *cp;
 | 
	
		
			
				|  |  | +  uint8_t challenge[OR_AUTH_CHALLENGE_LEN];
 | 
	
		
			
				|  |  | +  tor_assert(conn->_base.state == OR_CONN_STATE_OR_HANDSHAKING_V3);
 | 
	
		
			
				|  |  | +
 | 
	
		
			
				|  |  | +  if (! conn->handshake_state)
 | 
	
		
			
				|  |  | +    return -1;
 | 
	
		
			
				|  |  | +
 | 
	
		
			
				|  |  | +  if (crypto_rand((char*)challenge, OR_AUTH_CHALLENGE_LEN) < 0)
 | 
	
		
			
				|  |  | +    return -1;
 | 
	
		
			
				|  |  | +  cell = var_cell_new(OR_AUTH_CHALLENGE_LEN + 4);
 | 
	
		
			
				|  |  | +  cell->command = CELL_AUTH_CHALLENGE;
 | 
	
		
			
				|  |  | +  memcpy(cell->payload, challenge, OR_AUTH_CHALLENGE_LEN);
 | 
	
		
			
				|  |  | +  cp = cell->payload + OR_AUTH_CHALLENGE_LEN;
 | 
	
		
			
				|  |  | +  set_uint16(cp, htons(1)); /* We recognize one authentication type. */
 | 
	
		
			
				|  |  | +  set_uint16(cp+2, htons(AUTHTYPE_RSA_SHA256_TLSSECRET));
 | 
	
		
			
				|  |  | +
 | 
	
		
			
				|  |  | +  connection_or_write_var_cell_to_buf(cell, conn);
 | 
	
		
			
				|  |  | +  var_cell_free(cell);
 | 
	
		
			
				|  |  | +  memset(challenge, 0, sizeof(challenge));
 | 
	
		
			
				|  |  | +
 | 
	
		
			
				|  |  | +  return 0;
 | 
	
		
			
				|  |  | +}
 | 
	
		
			
				|  |  | +
 |