Ejemplo n.º 1
0
/* checks if ssl object was closed and can be removed */
int 
check_close(SSL *ssl) {
  int res, err, idx;
  struct sockaddr_storage peer;
  
  memset(&peer, 0, sizeof(peer));
  (void)BIO_dgram_get_peer(SSL_get_rbio(ssl), &peer);

  res = 0;
  if (SSL_get_shutdown(ssl) & SSL_RECEIVED_SHUTDOWN) {
    printf("SSL_RECEIVED_SHUTDOWN\n");
    res = SSL_shutdown(ssl);
    if (res == 0) {
      printf("must call SSL_shutdown again\n");
      res = SSL_shutdown(ssl);
    }
    if (res < 0) {
	err = SSL_get_error(ssl,res);	
	fprintf(stderr, "shutdown: SSL error %d: %s\n", err,
		ERR_error_string(err, NULL));
    } 

    /* we can close the SSL object anyway */
    /* FIXME: need to get ifindex from somewhere */
    idx = get_index_of_peer((struct sockaddr *)&peer, 0);
    OPENSSL_assert(idx < 0 || ssl == ssl_peer_storage[idx]->ssl);
    if (idx >= 0) {
      ssl_peer_storage[idx]->state = PEER_ST_CLOSED;
      printf("moved SSL object %d to CLOSED\n",idx);
    }
  }
  
  return res;
}
Ejemplo n.º 2
0
int dtls1_listen(SSL *s, struct sockaddr *client)
	{
	int ret;

	SSL_set_options(s, SSL_OP_COOKIE_EXCHANGE);
	s->d1->listen = 1;

	ret = SSL_accept(s);
	if (ret <= 0) return ret;
	
	(void) BIO_dgram_get_peer(SSL_get_rbio(s), client);
	return 1;
	}
Ejemplo n.º 3
0
int dtls1_listen(SSL *s, struct sockaddr *client)
	{
	int ret;

	/* Ensure there is no state left over from a previous invocation */
	SSL_clear(s);

	SSL_set_options(s, SSL_OP_COOKIE_EXCHANGE);
	s->d1->listen = 1;

	ret = SSL_accept(s);
	if (ret <= 0) return ret;
	
	(void) BIO_dgram_get_peer(SSL_get_rbio(s), client);
	return 1;
	}
Ejemplo n.º 4
0
int MS_CALLBACK generate_cookie_callback(SSL *ssl, unsigned char *cookie, unsigned int *cookie_len)
	{
	unsigned char *buffer, result[EVP_MAX_MD_SIZE];
	unsigned int length, resultlength;
	struct sockaddr_in peer;
	
	/* Initialize a random secret */
	if (!cookie_initialized)
		{
		if (!RAND_bytes(cookie_secret, COOKIE_SECRET_LENGTH))
			{
			BIO_printf(bio_err,"error setting random cookie secret\n");
			return 0;
			}
		cookie_initialized = 1;
		}

	/* Read peer information */
	(void)BIO_dgram_get_peer(SSL_get_rbio(ssl), &peer);

	/* Create buffer with peer's address and port */
	length = sizeof(peer.sin_addr);
	length += sizeof(peer.sin_port);
	buffer = OPENSSL_malloc(length);

	if (buffer == NULL)
		{
		BIO_printf(bio_err,"out of memory\n");
		return 0;
		}
	
	memcpy(buffer, &peer.sin_addr, sizeof(peer.sin_addr));
	memcpy(buffer + sizeof(peer.sin_addr), &peer.sin_port, sizeof(peer.sin_port));

	/* Calculate HMAC of buffer using the secret */
	HMAC(EVP_sha1(), cookie_secret, COOKIE_SECRET_LENGTH,
	     buffer, length, result, &resultlength);
	OPENSSL_free(buffer);

	memcpy(cookie, result, resultlength);
	*cookie_len = resultlength;

	return 1;
	}
Ejemplo n.º 5
0
void
check_peers() {
typedef struct bio_dgram_data_st
	{
	union {
		struct sockaddr sa;
		struct sockaddr_in sa_in;
		struct sockaddr_in6 sa_in6;
	} peer;
	unsigned int connected;
	unsigned int _errno;
	unsigned int mtu;
	struct timeval next_timeout;
	struct timeval socket_timeout;
	} bio_dgram_data;

  struct sockaddr_in6 peer;
  int i;
  BIO *bio;
  for (i = 0; i < MAX_SSL_PEERS; i++) {
    if (ssl_peer_storage[i]) {
      if (!ssl_peer_storage[i]->ssl)
	fprintf(stderr, "invalid SSL object for peer %d!\n",i);
      else {
	bio = SSL_get_rbio(ssl_peer_storage[i]->ssl);
	if (bio) {
	  (void) BIO_dgram_get_peer(bio, (struct sockaddr *)&peer);
	  if (peer.sin6_port && ssl_peer_storage[i]->h != ntohs(peer.sin6_port)) {
	    fprintf(stderr, "   bio %p: port differs from hash: %d != %d! (%sconnected)\n", bio,
		    ssl_peer_storage[i]->h, 
		    ntohs(((struct sockaddr_in6 *)&peer)->sin6_port),
		    ((bio_dgram_data *)bio->ptr)->connected ? "" : "not ");
	  }

	}
      }
    }
  }
}
Ejemplo n.º 6
0
int MS_CALLBACK verify_cookie_callback(SSL *ssl, unsigned char *cookie, unsigned int cookie_len)
	{
	unsigned char *buffer, result[EVP_MAX_MD_SIZE];
	unsigned int length, resultlength;
	struct sockaddr_in peer;
	
	/* If secret isn't initialized yet, the cookie can't be valid */
	if (!cookie_initialized)
		return 0;

	/* Read peer information */
	(void)BIO_dgram_get_peer(SSL_get_rbio(ssl), &peer);

	/* Create buffer with peer's address and port */
	length = sizeof(peer.sin_addr);
	length += sizeof(peer.sin_port);
	buffer = (unsigned char*) OPENSSL_malloc(length);
	
	if (buffer == NULL)
		{
		BIO_printf(bio_err,"out of memory\n");
		return 0;
		}
	
	memcpy(buffer, &peer.sin_addr, sizeof(peer.sin_addr));
	memcpy(buffer + sizeof(peer.sin_addr), &peer.sin_port, sizeof(peer.sin_port));

	/* Calculate HMAC of buffer using the secret */
	HMAC(EVP_sha1(), cookie_secret, COOKIE_SECRET_LENGTH,
	     buffer, length, result, &resultlength);
	OPENSSL_free(buffer);
	
	if (cookie_len == resultlength && memcmp(result, cookie, resultlength) == 0)
		return 1;

	return 0;
	}
Ejemplo n.º 7
0
int
verify_cookie_callback(SSL * ssl, const unsigned char *cookie,
    unsigned int cookie_len)
{
	unsigned char *buffer, result[EVP_MAX_MD_SIZE];
	unsigned int length, resultlength;
	union {
		struct sockaddr sa;
		struct sockaddr_in s4;
		struct sockaddr_in6 s6;
	} peer;

	/* If secret isn't initialized yet, the cookie can't be valid */
	if (!cookie_initialized)
		return 0;

	/* Read peer information */
	(void) BIO_dgram_get_peer(SSL_get_rbio(ssl), &peer);

	/* Create buffer with peer's address and port */
	length = 0;
	switch (peer.sa.sa_family) {
	case AF_INET:
		length += sizeof(struct in_addr);
		length += sizeof(peer.s4.sin_port);
		break;
	case AF_INET6:
		length += sizeof(struct in6_addr);
		length += sizeof(peer.s6.sin6_port);
		break;
	default:
		OPENSSL_assert(0);
		break;
	}
	buffer = malloc(length);

	if (buffer == NULL) {
		BIO_printf(bio_err, "out of memory\n");
		return 0;
	}
	switch (peer.sa.sa_family) {
	case AF_INET:
		memcpy(buffer, &peer.s4.sin_port, sizeof(peer.s4.sin_port));
		memcpy(buffer + sizeof(peer.s4.sin_port),
		    &peer.s4.sin_addr, sizeof(struct in_addr));
		break;
	case AF_INET6:
		memcpy(buffer, &peer.s6.sin6_port, sizeof(peer.s6.sin6_port));
		memcpy(buffer + sizeof(peer.s6.sin6_port),
		    &peer.s6.sin6_addr, sizeof(struct in6_addr));
		break;
	default:
		OPENSSL_assert(0);
		break;
	}

	/* Calculate HMAC of buffer using the secret */
	HMAC(EVP_sha1(), cookie_secret, COOKIE_SECRET_LENGTH,
	    buffer, length, result, &resultlength);
	free(buffer);

	if (cookie_len == resultlength &&
	    memcmp(result, cookie, resultlength) == 0)
		return 1;

	return 0;
}
Ejemplo n.º 8
0
int DTLSv1_listen(SSL *s, BIO_ADDR *client)
{
    int next, n, ret = 0, clearpkt = 0;
    unsigned char cookie[DTLS1_COOKIE_LENGTH];
    unsigned char seq[SEQ_NUM_SIZE];
    const unsigned char *data;
    unsigned char *p, *buf;
    unsigned long reclen, fragoff, fraglen, msglen;
    unsigned int rectype, versmajor, msgseq, msgtype, clientvers, cookielen;
    BIO *rbio, *wbio;
    BUF_MEM *bufm;
    BIO_ADDR *tmpclient = NULL;
    PACKET pkt, msgpkt, msgpayload, session, cookiepkt;

    /* Ensure there is no state left over from a previous invocation */
    if (!SSL_clear(s))
        return -1;

    ERR_clear_error();

    rbio = SSL_get_rbio(s);
    wbio = SSL_get_wbio(s);

    if (!rbio || !wbio) {
        SSLerr(SSL_F_DTLSV1_LISTEN, SSL_R_BIO_NOT_SET);
        return -1;
    }

    /*
     * We only peek at incoming ClientHello's until we're sure we are going to
     * to respond with a HelloVerifyRequest. If its a ClientHello with a valid
     * cookie then we leave it in the BIO for accept to handle.
     */
    BIO_ctrl(SSL_get_rbio(s), BIO_CTRL_DGRAM_SET_PEEK_MODE, 1, NULL);

    /*
     * Note: This check deliberately excludes DTLS1_BAD_VER because that version
     * requires the MAC to be calculated *including* the first ClientHello
     * (without the cookie). Since DTLSv1_listen is stateless that cannot be
     * supported. DTLS1_BAD_VER must use cookies in a stateful manner (e.g. via
     * SSL_accept)
     */
    if ((s->version & 0xff00) != (DTLS1_VERSION & 0xff00)) {
        SSLerr(SSL_F_DTLSV1_LISTEN, SSL_R_UNSUPPORTED_SSL_VERSION);
        return -1;
    }

    if (s->init_buf == NULL) {
        if ((bufm = BUF_MEM_new()) == NULL) {
            SSLerr(SSL_F_DTLSV1_LISTEN, ERR_R_MALLOC_FAILURE);
            return -1;
        }

        if (!BUF_MEM_grow(bufm, SSL3_RT_MAX_PLAIN_LENGTH)) {
            BUF_MEM_free(bufm);
            SSLerr(SSL_F_DTLSV1_LISTEN, ERR_R_MALLOC_FAILURE);
            return -1;
        }
        s->init_buf = bufm;
    }
    buf = (unsigned char *)s->init_buf->data;

    do {
        /* Get a packet */

        clear_sys_error();
        /*
         * Technically a ClientHello could be SSL3_RT_MAX_PLAIN_LENGTH
         * + DTLS1_RT_HEADER_LENGTH bytes long. Normally init_buf does not store
         * the record header as well, but we do here. We've set up init_buf to
         * be the standard size for simplicity. In practice we shouldn't ever
         * receive a ClientHello as long as this. If we do it will get dropped
         * in the record length check below.
         */
        n = BIO_read(rbio, buf, SSL3_RT_MAX_PLAIN_LENGTH);

        if (n <= 0) {
            if (BIO_should_retry(rbio)) {
                /* Non-blocking IO */
                goto end;
            }
            return -1;
        }

        /* If we hit any problems we need to clear this packet from the BIO */
        clearpkt = 1;

        if (!PACKET_buf_init(&pkt, buf, n)) {
            SSLerr(SSL_F_DTLSV1_LISTEN, ERR_R_INTERNAL_ERROR);
            return -1;
        }

        /*
         * Parse the received record. If there are any problems with it we just
         * dump it - with no alert. RFC6347 says this "Unlike TLS, DTLS is
         * resilient in the face of invalid records (e.g., invalid formatting,
         * length, MAC, etc.).  In general, invalid records SHOULD be silently
         * discarded, thus preserving the association; however, an error MAY be
         * logged for diagnostic purposes."
         */

        /* this packet contained a partial record, dump it */
        if (n < DTLS1_RT_HEADER_LENGTH) {
            SSLerr(SSL_F_DTLSV1_LISTEN, SSL_R_RECORD_TOO_SMALL);
            goto end;
        }

        if (s->msg_callback)
            s->msg_callback(0, 0, SSL3_RT_HEADER, buf,
                            DTLS1_RT_HEADER_LENGTH, s, s->msg_callback_arg);

        /* Get the record header */
        if (!PACKET_get_1(&pkt, &rectype)
            || !PACKET_get_1(&pkt, &versmajor)) {
            SSLerr(SSL_F_DTLSV1_LISTEN, SSL_R_LENGTH_MISMATCH);
            goto end;
        }

        if (rectype != SSL3_RT_HANDSHAKE) {
            SSLerr(SSL_F_DTLSV1_LISTEN, SSL_R_UNEXPECTED_MESSAGE);
            goto end;
        }

        /*
         * Check record version number. We only check that the major version is
         * the same.
         */
        if (versmajor != DTLS1_VERSION_MAJOR) {
            SSLerr(SSL_F_DTLSV1_LISTEN, SSL_R_BAD_PROTOCOL_VERSION_NUMBER);
            goto end;
        }

        if (!PACKET_forward(&pkt, 1)
            /* Save the sequence number: 64 bits, with top 2 bytes = epoch */
            || !PACKET_copy_bytes(&pkt, seq, SEQ_NUM_SIZE)
            || !PACKET_get_length_prefixed_2(&pkt, &msgpkt)) {
            SSLerr(SSL_F_DTLSV1_LISTEN, SSL_R_LENGTH_MISMATCH);
            goto end;
        }
        /*
         * We allow data remaining at the end of the packet because there could
         * be a second record (but we ignore it)
         */

        /* This is an initial ClientHello so the epoch has to be 0 */
        if (seq[0] != 0 || seq[1] != 0) {
            SSLerr(SSL_F_DTLSV1_LISTEN, SSL_R_UNEXPECTED_MESSAGE);
            goto end;
        }

        /* Get a pointer to the raw message for the later callback */
        data = PACKET_data(&msgpkt);

        /* Finished processing the record header, now process the message */
        if (!PACKET_get_1(&msgpkt, &msgtype)
            || !PACKET_get_net_3(&msgpkt, &msglen)
            || !PACKET_get_net_2(&msgpkt, &msgseq)
            || !PACKET_get_net_3(&msgpkt, &fragoff)
            || !PACKET_get_net_3(&msgpkt, &fraglen)
            || !PACKET_get_sub_packet(&msgpkt, &msgpayload, fraglen)
            || PACKET_remaining(&msgpkt) != 0) {
            SSLerr(SSL_F_DTLSV1_LISTEN, SSL_R_LENGTH_MISMATCH);
            goto end;
        }

        if (msgtype != SSL3_MT_CLIENT_HELLO) {
            SSLerr(SSL_F_DTLSV1_LISTEN, SSL_R_UNEXPECTED_MESSAGE);
            goto end;
        }

        /* Message sequence number can only be 0 or 1 */
        if (msgseq > 2) {
            SSLerr(SSL_F_DTLSV1_LISTEN, SSL_R_INVALID_SEQUENCE_NUMBER);
            goto end;
        }

        /*
         * We don't support fragment reassembly for ClientHellos whilst
         * listening because that would require server side state (which is
         * against the whole point of the ClientHello/HelloVerifyRequest
         * mechanism). Instead we only look at the first ClientHello fragment
         * and require that the cookie must be contained within it.
         */
        if (fragoff != 0 || fraglen > msglen) {
            /* Non initial ClientHello fragment (or bad fragment) */
            SSLerr(SSL_F_DTLSV1_LISTEN, SSL_R_FRAGMENTED_CLIENT_HELLO);
            goto end;
        }

        if (s->msg_callback)
            s->msg_callback(0, s->version, SSL3_RT_HANDSHAKE, data,
                            fraglen + DTLS1_HM_HEADER_LENGTH, s,
                            s->msg_callback_arg);

        if (!PACKET_get_net_2(&msgpayload, &clientvers)) {
            SSLerr(SSL_F_DTLSV1_LISTEN, SSL_R_LENGTH_MISMATCH);
            goto end;
        }

        /*
         * Verify client version is supported
         */
        if (DTLS_VERSION_LT(clientvers, (unsigned int)s->method->version) &&
            s->method->version != DTLS_ANY_VERSION) {
            SSLerr(SSL_F_DTLSV1_LISTEN, SSL_R_WRONG_VERSION_NUMBER);
            goto end;
        }

        if (!PACKET_forward(&msgpayload, SSL3_RANDOM_SIZE)
            || !PACKET_get_length_prefixed_1(&msgpayload, &session)
            || !PACKET_get_length_prefixed_1(&msgpayload, &cookiepkt)) {
            /*
             * Could be malformed or the cookie does not fit within the initial
             * ClientHello fragment. Either way we can't handle it.
             */
            SSLerr(SSL_F_DTLSV1_LISTEN, SSL_R_LENGTH_MISMATCH);
            goto end;
        }

        /*
         * Check if we have a cookie or not. If not we need to send a
         * HelloVerifyRequest.
         */
        if (PACKET_remaining(&cookiepkt) == 0) {
            next = LISTEN_SEND_VERIFY_REQUEST;
        } else {
            /*
             * We have a cookie, so lets check it.
             */
            if (s->ctx->app_verify_cookie_cb == NULL) {
                SSLerr(SSL_F_DTLSV1_LISTEN, SSL_R_NO_VERIFY_COOKIE_CALLBACK);
                /* This is fatal */
                return -1;
            }
            if (s->ctx->app_verify_cookie_cb(s, PACKET_data(&cookiepkt),
                                             PACKET_remaining(&cookiepkt)) ==
                0) {
                /*
                 * We treat invalid cookies in the same was as no cookie as
                 * per RFC6347
                 */
                next = LISTEN_SEND_VERIFY_REQUEST;
            } else {
                /* Cookie verification succeeded */
                next = LISTEN_SUCCESS;
            }
        }

        if (next == LISTEN_SEND_VERIFY_REQUEST) {
            /*
             * There was no cookie in the ClientHello so we need to send a
             * HelloVerifyRequest. If this fails we do not worry about trying
             * to resend, we just drop it.
             */

            /*
             * Dump the read packet, we don't need it any more. Ignore return
             * value
             */
            BIO_ctrl(SSL_get_rbio(s), BIO_CTRL_DGRAM_SET_PEEK_MODE, 0, NULL);
            BIO_read(rbio, buf, SSL3_RT_MAX_PLAIN_LENGTH);
            BIO_ctrl(SSL_get_rbio(s), BIO_CTRL_DGRAM_SET_PEEK_MODE, 1, NULL);

            /* Generate the cookie */
            if (s->ctx->app_gen_cookie_cb == NULL ||
                s->ctx->app_gen_cookie_cb(s, cookie, &cookielen) == 0 ||
                cookielen > 255) {
                SSLerr(SSL_F_DTLSV1_LISTEN, SSL_R_COOKIE_GEN_CALLBACK_FAILURE);
                /* This is fatal */
                return -1;
            }

            p = &buf[DTLS1_RT_HEADER_LENGTH];
            msglen = dtls_raw_hello_verify_request(p + DTLS1_HM_HEADER_LENGTH,
                                                   cookie, cookielen);

            *p++ = DTLS1_MT_HELLO_VERIFY_REQUEST;

            /* Message length */
            l2n3(msglen, p);

            /* Message sequence number is always 0 for a HelloVerifyRequest */
            s2n(0, p);

            /*
             * We never fragment a HelloVerifyRequest, so fragment offset is 0
             * and fragment length is message length
             */
            l2n3(0, p);
            l2n3(msglen, p);

            /* Set reclen equal to length of whole handshake message */
            reclen = msglen + DTLS1_HM_HEADER_LENGTH;

            /* Add the record header */
            p = buf;

            *(p++) = SSL3_RT_HANDSHAKE;
            /*
             * Special case: for hello verify request, client version 1.0 and we
             * haven't decided which version to use yet send back using version
             * 1.0 header: otherwise some clients will ignore it.
             */
            if (s->method->version == DTLS_ANY_VERSION) {
                *(p++) = DTLS1_VERSION >> 8;
                *(p++) = DTLS1_VERSION & 0xff;
            } else {
                *(p++) = s->version >> 8;
                *(p++) = s->version & 0xff;
            }

            /*
             * Record sequence number is always the same as in the received
             * ClientHello
             */
            memcpy(p, seq, SEQ_NUM_SIZE);
            p += SEQ_NUM_SIZE;

            /* Length */
            s2n(reclen, p);

            /*
             * Set reclen equal to length of whole record including record
             * header
             */
            reclen += DTLS1_RT_HEADER_LENGTH;

            if (s->msg_callback)
                s->msg_callback(1, 0, SSL3_RT_HEADER, buf,
                                DTLS1_RT_HEADER_LENGTH, s, s->msg_callback_arg);

            if ((tmpclient = BIO_ADDR_new()) == NULL) {
                SSLerr(SSL_F_DTLSV1_LISTEN, ERR_R_MALLOC_FAILURE);
                goto end;
            }

            /*
             * This is unnecessary if rbio and wbio are one and the same - but
             * maybe they're not. We ignore errors here - some BIOs do not
             * support this.
             */
            if (BIO_dgram_get_peer(rbio, tmpclient) > 0) {
                (void)BIO_dgram_set_peer(wbio, tmpclient);
            }
            BIO_ADDR_free(tmpclient);
            tmpclient = NULL;

            if (BIO_write(wbio, buf, reclen) < (int)reclen) {
                if (BIO_should_retry(wbio)) {
                    /*
                     * Non-blocking IO...but we're stateless, so we're just
                     * going to drop this packet.
                     */
                    goto end;
                }
                return -1;
            }

            if (BIO_flush(wbio) <= 0) {
                if (BIO_should_retry(wbio)) {
                    /*
                     * Non-blocking IO...but we're stateless, so we're just
                     * going to drop this packet.
                     */
                    goto end;
                }
                return -1;
            }
        }
Ejemplo n.º 9
0
int MS_CALLBACK generate_cookie_callback(SSL *ssl, unsigned char *cookie, unsigned int *cookie_len)
	{
	unsigned char *buffer, result[EVP_MAX_MD_SIZE];
	unsigned int length, resultlength;
	union {
		struct sockaddr sa;
		struct sockaddr_in s4;
#if OPENSSL_USE_IPV6
		struct sockaddr_in6 s6;
#endif
	} peer;

	/* Initialize a random secret */
	if (!cookie_initialized)
		{
		if (!RAND_bytes(cookie_secret, COOKIE_SECRET_LENGTH))
			{
			BIO_printf(bio_err,"error setting random cookie secret\n");
			return 0;
			}
		cookie_initialized = 1;
		}

	/* Read peer information */
	(void)BIO_dgram_get_peer(SSL_get_rbio(ssl), &peer);

	/* Create buffer with peer's address and port */
	length = 0;
	switch (peer.sa.sa_family)
		{
	case AF_INET:
		length += sizeof(struct in_addr);
		length += sizeof(peer.s4.sin_port);
		break;
#if OPENSSL_USE_IPV6
	case AF_INET6:
		length += sizeof(struct in6_addr);
		length += sizeof(peer.s6.sin6_port);
		break;
#endif
	default:
		OPENSSL_assert(0);
		break;
		}
	buffer = OPENSSL_malloc(length);

	if (buffer == NULL)
		{
		BIO_printf(bio_err,"out of memory\n");
		return 0;
		}

	switch (peer.sa.sa_family)
		{
	case AF_INET:
		memcpy(buffer,
		       &peer.s4.sin_port,
		       sizeof(peer.s4.sin_port));
		memcpy(buffer + sizeof(peer.s4.sin_port),
		       &peer.s4.sin_addr,
		       sizeof(struct in_addr));
		break;
#if OPENSSL_USE_IPV6
	case AF_INET6:
		memcpy(buffer,
		       &peer.s6.sin6_port,
		       sizeof(peer.s6.sin6_port));
		memcpy(buffer + sizeof(peer.s6.sin6_port),
		       &peer.s6.sin6_addr,
		       sizeof(struct in6_addr));
		break;
#endif
	default:
		OPENSSL_assert(0);
		break;
		}

	/* Calculate HMAC of buffer using the secret */
	HMAC(EVP_sha1(), cookie_secret, COOKIE_SECRET_LENGTH,
	     buffer, length, result, &resultlength);
	OPENSSL_free(buffer);

	memcpy(cookie, result, resultlength);
	*cookie_len = resultlength;

	return 1;
	}
Ejemplo n.º 10
0
static int generate_cookie(SSL *ssl, unsigned char *cookie, unsigned int *cookie_len)
{
  unsigned char *buffer, result[EVP_MAX_MD_SIZE];
  unsigned int length = 0, resultlength;
  union {
    struct sockaddr_storage ss;
    struct sockaddr_in6 s6;
    struct sockaddr_in s4;
  } peer;

  /* Initialize a random secret */
  if (!cookie_initialized)
    {
      if (!RAND_bytes(cookie_secret, COOKIE_SECRET_LENGTH))
	{
	  printf("error setting random cookie secret\n");
	  return 0;
	}
      cookie_initialized = 1;
    }

  /* Read peer information */
  (void) BIO_dgram_get_peer(SSL_get_rbio(ssl), &peer);

  /* Create buffer with peer's address and port */
  length = 0;
  switch (peer.ss.ss_family) {
  case AF_INET:
    length += sizeof(struct in_addr);
    break;
  case AF_INET6:
    length += sizeof(struct in6_addr);
    break;
  default:
    OPENSSL_assert(0);
    break;
  }
  length += sizeof(in_port_t);
  buffer = (unsigned char*) OPENSSL_malloc(length);

  if (buffer == NULL)
    {
      printf("out of memory\n");
      return 0;
    }

  switch (peer.ss.ss_family) {
  case AF_INET:
    memcpy(buffer,
	   &peer.s4.sin_port,
	   sizeof(in_port_t));
    memcpy(buffer + sizeof(peer.s4.sin_port),
	   &peer.s4.sin_addr,
	   sizeof(struct in_addr));
    break;
  case AF_INET6:
    memcpy(buffer,
	   &peer.s6.sin6_port,
	   sizeof(in_port_t));
    memcpy(buffer + sizeof(in_port_t),
	   &peer.s6.sin6_addr,
	   sizeof(struct in6_addr));
    break;
  default:
    OPENSSL_assert(0);
    break;
  }

  /* Calculate HMAC of buffer using the secret */
  HMAC(EVP_sha1(), (const void*) cookie_secret, COOKIE_SECRET_LENGTH,
       (const unsigned char*) buffer, length, result, &resultlength);
  OPENSSL_free(buffer);

  memcpy(cookie, result, resultlength);
  *cookie_len = resultlength;

  return 1;
}
Ejemplo n.º 11
0
static int generate_cookie(SSL *ssl, unsigned char *cookie, unsigned int *cookie_len)
{
  unsigned char *buffer, result[EVP_MAX_MD_SIZE];
  unsigned int length = 0, resultlength;
  ioa_addr peer;

  unsigned char cookie_secret[COOKIE_SECRET_LENGTH];
  calculate_cookie(ssl, cookie_secret, sizeof(cookie_secret));
  
  /* Read peer information */
  (void) BIO_dgram_get_peer(SSL_get_wbio(ssl), &peer);
  
  /* Create buffer with peer's address and port */
  length = 0;
  switch (peer.ss.ss_family) {
  case AF_INET:
    length += sizeof(struct in_addr);
    break;
  case AF_INET6:
    length += sizeof(struct in6_addr);
    break;
  default:
    OPENSSL_assert(0);
    break;
  }
  length += sizeof(in_port_t);
  buffer = (unsigned char*) OPENSSL_malloc(length);
  
  if (buffer == NULL) {
    TURN_LOG_FUNC(TURN_LOG_LEVEL_INFO,"out of memory\n");
    return 0;
  }
  
  switch (peer.ss.ss_family) {
  case AF_INET:
    memcpy(buffer,
	   &peer.s4.sin_port,
	   sizeof(in_port_t));
    memcpy(buffer + sizeof(peer.s4.sin_port),
	   &peer.s4.sin_addr,
	   sizeof(struct in_addr));
    break;
  case AF_INET6:
    memcpy(buffer,
	   &peer.s6.sin6_port,
	   sizeof(in_port_t));
    memcpy(buffer + sizeof(in_port_t),
	   &peer.s6.sin6_addr,
	   sizeof(struct in6_addr));
    break;
  default:
    OPENSSL_assert(0);
    break;
  }
  
  /* Calculate HMAC of buffer using the secret */
  HMAC(EVP_sha1(), (const void*) cookie_secret, COOKIE_SECRET_LENGTH,
       (const unsigned char*) buffer, length, result, &resultlength);
  OPENSSL_free(buffer);
  
  memcpy(cookie, result, resultlength);
  *cookie_len = resultlength;
  
  return 1;
}
Ejemplo n.º 12
0
/**
 * This function tracks the status changes from libssl to manage local
 * object state.
 */
void
info_callback(const SSL *ssl, int where, int ret) {
  int idx, i;
  struct sockaddr_storage peer;
  struct sockaddr_storage peer2;
  char addr[INET6_ADDRSTRLEN];
  char port[6];

  if (where & SSL_CB_LOOP)  /* do not care for intermediary states */
    return;

  memset(&peer, 0, sizeof(peer));
  (void) BIO_dgram_get_peer(SSL_get_rbio(ssl), &peer);

  /* lookup SSL object */   /* FIXME: need to get the ifindex */
  idx = get_index_of_peer((struct sockaddr *)&peer, 0);
  
  if (idx >= 0)
    fprintf(stderr, "info_callback: assert: %d < 0 || %p == %p (storage: %p)\n",
	    idx, ssl, ssl_peer_storage[idx]->ssl, ssl_peer_storage[idx]); 
  if (idx >= 0 && ssl != ssl_peer_storage[idx]->ssl) {
    getnameinfo((struct sockaddr *)&peer, sizeof(peer), 
		addr, sizeof(addr), port, sizeof(port), 
		NI_NUMERICHOST | NI_NUMERICSERV);

    fprintf(stderr," ssl: [%s]:%s   ", addr, port);
    
    (void) BIO_dgram_get_peer(SSL_get_rbio(ssl_peer_storage[idx]->ssl), &peer2);
    getnameinfo((struct sockaddr *)&peer2, sizeof(peer2), 
		addr, sizeof(addr), port, sizeof(port), 
		NI_NUMERICHOST | NI_NUMERICSERV);

    fprintf(stderr," ssl_peer_storage[idx]->ssl: [%s]:%s\n", addr, port);

    fprintf(stderr, " hash:%lu     h: %lu\n",
	    hash_peer((const struct sockaddr *)&peer, 0),
	    ssl_peer_storage[idx]->h);

    for (i = 0; i < MAX_SSL_PEERS; i++) {
      if (ssl_peer_storage[i]) {
	fprintf(stderr, "%02d: %p ssl: %p  ",
		i, ssl_peer_storage[i] ,ssl_peer_storage[i]->ssl);

	(void) BIO_dgram_get_peer(SSL_get_rbio(ssl_peer_storage[i]->ssl), &peer2);
	getnameinfo((struct sockaddr *)&peer2, sizeof(peer2), 
		    addr, sizeof(addr), port, sizeof(port), 
		    NI_NUMERICHOST | NI_NUMERICSERV);
	
	fprintf(stderr," peer: [%s]:%s    h: %lu\n", addr, port, ssl_peer_storage[i]->h);
      }
    }
    fprintf(stderr, "***** ASSERT FAILED ******\n");

    memset(&peer, 0, sizeof(peer));
    (void) BIO_dgram_get_peer(SSL_get_wbio(ssl), &peer);

    idx = get_index_of_peer((struct sockaddr *)&peer, 0);
    fprintf(stderr, "  get_index_of_peer for wbio returns %d, type is %04x\n",
	    idx, where);    
  }
#if 1
	  check_peers();
  OPENSSL_assert((idx < 0) || (ssl == ssl_peer_storage[idx]->ssl));
#endif

  if (where & SSL_CB_ALERT) {
#ifndef NDEBUG
    if (ret != 0)
      fprintf(stderr,"%s:%s:%s\n", SSL_alert_type_string(ret),
	      SSL_alert_desc_string(ret), SSL_alert_desc_string_long(ret));
#endif

    /* examine alert type */
    switch (*SSL_alert_type_string(ret)) {
    case 'F':
      /* move SSL object from pending to close */
      if (idx >= 0) {
	ssl_peer_storage[idx]->state = PEER_ST_CLOSED;
	pending--;
      }
      break;
    case 'W': 
      if ((ret & 0xff) == SSL_AD_CLOSE_NOTIFY) {
	if (where == SSL_CB_WRITE_ALERT) 
	  fprintf(stderr,"sent CLOSE_NOTIFY\n");
	else /* received CN */
	  fprintf(stderr,"received CLOSE_NOTIFY\n");
      }
      break;
    default: 			/* handle unknown alert types */
#ifndef NDEBUG
      printf("not handled!\n");
#endif
    }
  }

  if (where & SSL_CB_HANDSHAKE_DONE) {
    /* move SSL object from pending to established */
    printf("HANDSHAKE_DONE ");
    if (idx >= 0) {
      
      if (ssl_peer_storage[idx]->state == PEER_ST_PENDING) {
	ssl_peer_storage[idx]->state = PEER_ST_ESTABLISHED;
	pending--;
	printf("moved SSL object %d to ESTABLISHED\n", idx);
	printf("%d objects pending\n", pending);
      } else {
#ifndef NDEBUG
	printf("huh, object %d was not pending? (%d)\n", idx,
	       ssl_peer_storage[idx]->state);
#endif
      }
      return;
    }
    return;
  }

  return;
}
Ejemplo n.º 13
0
SSL *
get_ssl(SSL_CTX *ctx, int sockfd, struct sockaddr *src, int ifindex) {
  int idx;
  BIO *bio;
  SSL *ssl;
#ifndef NDEBUG
  struct sockaddr_storage peer;
  char addr[INET6_ADDRSTRLEN];
  char port[6];
  int i;
#endif

  idx = get_index_of_peer(src,ifindex);
  if (idx >= 0) {
    fprintf(stderr,"found peer %d ",idx);
    switch (ssl_peer_storage[idx]->state) {
    case PEER_ST_ESTABLISHED: fprintf(stderr,"established\n"); break;
    case PEER_ST_PENDING:     fprintf(stderr,"pending\n"); break;
    case PEER_ST_CLOSED:      fprintf(stderr,"closed\n"); break;
    default:
      OPENSSL_assert(0);
    }

#ifndef NDEBUG
    memset(&peer, 0, sizeof(peer));
    (void) BIO_dgram_get_peer(SSL_get_rbio(ssl_peer_storage[idx]->ssl), &peer);

    getnameinfo((struct sockaddr *)&peer, sizeof(peer), 
		addr, sizeof(addr), port, sizeof(port), 
		NI_NUMERICHOST | NI_NUMERICSERV);

    fprintf(stderr,"      [%s]:%s   \n", addr, port);
#endif
    return ssl_peer_storage[idx]->ssl;
  }

  /* none found, create new if sufficient space available */
  if (pending < MAX_SSL_PENDING) {
    for (idx = 0; idx < MAX_SSL_PEERS; idx++) {
      if (ssl_peer_storage[idx] == NULL) { /* found space */
	ssl = SSL_new(ctx);
	
	if (ssl) {
	  bio = BIO_new_dgram(sockfd, BIO_NOCLOSE);
	  if (!bio) {
	    SSL_free(ssl);
	    return NULL;
	  }
	  
	  SSL_set_bio(ssl, bio, bio);
	  SSL_set_options(ssl, SSL_OP_COOKIE_EXCHANGE);
	  
	  SSL_set_accept_state(ssl);
	  ssl_peer_storage[idx] = (ssl_peer_t *) malloc(sizeof(ssl_peer_t));
	  if (!ssl_peer_storage[idx]) {
	    SSL_free(ssl);
	    return NULL;
	  }
	  ssl_peer_storage[idx]->state = PEER_ST_PENDING;
	  ssl_peer_storage[idx]->h = hash_peer(src,ifindex);
	  ssl_peer_storage[idx]->ssl = ssl;
	  
	  pending++;
	  
	  fprintf(stderr,
		  "created new SSL peer %d for ssl object %p (storage: %p)\n", 
		 idx, ssl, ssl_peer_storage[idx]);
#ifndef NDEBUG
    if (getnameinfo((struct sockaddr *)&src, sizeof(src), 
		addr, sizeof(addr), port, sizeof(port), 
		    NI_NUMERICHOST | NI_NUMERICSERV) != 0) {
      perror("getnameinfo");
      fprintf(stderr, "port was %u\n", ntohs(((struct sockaddr_in6 *)src)->sin6_port));
    } else {
    fprintf(stderr,"      [%s]:%s   \n", addr, port);
      }
#endif
    OPENSSL_assert(ssl_peer_storage[idx]->ssl == ssl);
	  fprintf(stderr,"%d objects pending\n", pending);
	  check_peers();
	  return ssl;
	}
      }
    }
  } else {
    fprintf(stderr, "too many pending SSL objects\n");
    return NULL;
  }

  fprintf(stderr, "too many peers\n");
  return NULL;
}
Ejemplo n.º 14
0
int MS_CALLBACK verify_cookie_callback(SSL *ssl, unsigned char *cookie, unsigned int cookie_len)
	{
	unsigned char *buffer, result[EVP_MAX_MD_SIZE];
	unsigned int length, resultlength;
	union {
		struct TINYCLR_SSL_SOCKADDR sa;
		struct TINYCLR_SSL_SOCKADDR_IN s4;
#if OPENSSL_USE_IPV6
		struct sockaddr_in6 s6;
#endif
	} peer;

	/* If secret isn't initialized yet, the cookie can't be valid */
	if (!cookie_initialized)
		return 0;

	/* Read peer information */
	(void)BIO_dgram_get_peer(SSL_get_rbio(ssl), &peer);

	/* Create buffer with peer's address and port */
	length = 0;
	switch (peer.sa.sa_family)
		{
	case AF_INET:
		length += sizeof(struct in_addr);
		length += sizeof(peer.s4.sin_port);
		break;
#if OPENSSL_USE_IPV6
	case AF_INET6:
		length += sizeof(struct in6_addr);
		length += sizeof(peer.s6.sin6_port);
		break;
#endif
	default:
		TINYCLR_SSL_ASSERT(0);
		break;
		}
	buffer = (unsigned char*)OPENSSL_malloc(length);
	
	if (buffer == NULL)
		{
		BIO_printf(bio_err,"out of memory\n");
		return 0;
		}

	switch (peer.sa.sa_family)
		{
	case AF_INET:
		TINYCLR_SSL_MEMCPY(buffer,
		       &peer.s4.sin_port,
		       sizeof(peer.s4.sin_port));
		TINYCLR_SSL_MEMCPY(buffer + sizeof(peer.s4.sin_port),
		       &peer.s4.sin_addr,
		       sizeof(struct in_addr));
		break;
#if OPENSSL_USE_IPV6
	case AF_INET6:
		TINYCLR_SSL_MEMCPY(buffer,
		       &peer.s6.sin6_port,
		       sizeof(peer.s6.sin6_port));
		TINYCLR_SSL_MEMCPY(buffer + sizeof(peer.s6.sin6_port),
		       &peer.s6.sin6_addr,
		       sizeof(struct in6_addr));
		break;
#endif
	default:
		TINYCLR_SSL_ASSERT(0);
		break;
		}

	/* Calculate HMAC of buffer using the secret */
	HMAC(EVP_sha1(), cookie_secret, COOKIE_SECRET_LENGTH,
	     buffer, length, result, &resultlength);
	OPENSSL_free(buffer);

	if (cookie_len == resultlength && TINYCLR_SSL_MEMCMP(result, cookie, resultlength) == 0)
		return 1;

	return 0;
	}
Ejemplo n.º 15
0
int DataPlaneServer::verify_cookie(SSL *ssl, unsigned char *cookie, unsigned int cookie_len) {
    unsigned char *buffer, result[EVP_MAX_MD_SIZE];
        unsigned int length = 0, resultlength;
        union {
            struct sockaddr_storage ss;
            struct sockaddr_in6 s6;
            struct sockaddr_in s4;
        } peer;

        /* If secret isn't initialized yet, the cookie can't be valid */
        if (!cookie_initialized)
            return 0;

        /* Read peer information */
        (void) BIO_dgram_get_peer(SSL_get_rbio(ssl), &peer);

        /* Create buffer with peer's address and port */
        length = 0;
        switch (peer.ss.ss_family) {
            case AF_INET:
                length += sizeof(struct in_addr);
                break;
            case AF_INET6:
                length += sizeof(struct in6_addr);
                break;
            default:
                OPENSSL_assert(0);
                break;
        }
        length += sizeof(in_port_t);
        buffer = (unsigned char*) OPENSSL_malloc(length);

        if (buffer == NULL) {
            qWarning("out of memory");
            return 0;
        }

        switch (peer.ss.ss_family) {
            case AF_INET:
                memcpy(buffer,
                       &peer.s4.sin_port,
                       sizeof(in_port_t));
                memcpy(buffer + sizeof(in_port_t),
                       &peer.s4.sin_addr,
                       sizeof(struct in_addr));
                break;
            case AF_INET6:
                memcpy(buffer,
                       &peer.s6.sin6_port,
                       sizeof(in_port_t));
                memcpy(buffer + sizeof(in_port_t),
                       &peer.s6.sin6_addr,
                       sizeof(struct in6_addr));
                break;
            default:
                OPENSSL_assert(0);
                break;
        }

        /* Calculate HMAC of buffer using the secret */
        HMAC(EVP_sha1(), (const void*) cookie_secret, COOKIE_SECRET_LENGTH,
             (const unsigned char*) buffer, length, result, &resultlength);
        OPENSSL_free(buffer);

        if (cookie_len == resultlength && memcmp(result, cookie, resultlength) == 0)
            return 1;

        return 0;
}