|
Packit Service |
4684c1 |
/*
|
|
Packit Service |
4684c1 |
* Copyright (C) 2007-2016 Free Software Foundation, Inc.
|
|
Packit Service |
4684c1 |
* Copyright (C) 2015-2016 Red Hat, Inc.
|
|
Packit Service |
4684c1 |
*
|
|
Packit Service |
4684c1 |
* Author: Simon Josefsson, Nikos Mavrogiannopoulos, Martin Ukrop
|
|
Packit Service |
4684c1 |
*
|
|
Packit Service |
4684c1 |
* This file is part of GnuTLS.
|
|
Packit Service |
4684c1 |
*
|
|
Packit Service |
4684c1 |
* The GnuTLS is free software; you can redistribute it and/or
|
|
Packit Service |
4684c1 |
* modify it under the terms of the GNU Lesser General Public License
|
|
Packit Service |
4684c1 |
* as published by the Free Software Foundation; either version 2.1 of
|
|
Packit Service |
4684c1 |
* the License, or (at your option) any later version.
|
|
Packit Service |
4684c1 |
*
|
|
Packit Service |
4684c1 |
* This library is distributed in the hope that it will be useful, but
|
|
Packit Service |
4684c1 |
* WITHOUT ANY WARRANTY; without even the implied warranty of
|
|
Packit Service |
4684c1 |
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
|
|
Packit Service |
4684c1 |
* Lesser General Public License for more details.
|
|
Packit Service |
4684c1 |
*
|
|
Packit Service |
4684c1 |
* You should have received a copy of the GNU Lesser General Public License
|
|
Packit Service |
4684c1 |
* along with this program. If not, see <https://www.gnu.org/licenses/>
|
|
Packit Service |
4684c1 |
*
|
|
Packit Service |
4684c1 |
*/
|
|
Packit Service |
4684c1 |
|
|
Packit Service |
4684c1 |
#include "gnutls_int.h"
|
|
Packit Service |
4684c1 |
#include "ip.h"
|
|
Packit Service |
4684c1 |
#include <gnutls/x509.h>
|
|
Packit Service |
4684c1 |
#include <arpa/inet.h>
|
|
Packit Service |
4684c1 |
|
|
Packit Service |
4684c1 |
/*-
|
|
Packit Service |
4684c1 |
* _gnutls_mask_to_prefix:
|
|
Packit Service |
4684c1 |
* @mask: CIDR mask
|
|
Packit Service |
4684c1 |
* @mask_size: number of bytes in @mask
|
|
Packit Service |
4684c1 |
*
|
|
Packit Service |
4684c1 |
* Check for mask validity (form of 1*0*) and return its prefix numerically.
|
|
Packit Service |
4684c1 |
*
|
|
Packit Service |
4684c1 |
* Returns: Length of 1-prefix (0 -- mask_size*8), -1 in case of invalid mask
|
|
Packit Service |
4684c1 |
-*/
|
|
Packit Service |
4684c1 |
int _gnutls_mask_to_prefix(const unsigned char *mask, unsigned mask_size)
|
|
Packit Service |
4684c1 |
{
|
|
Packit Service |
4684c1 |
unsigned i, prefix_length = 0;
|
|
Packit Service |
4684c1 |
for (i=0; i
|
|
Packit Service |
4684c1 |
if (mask[i] == 0xFF) {
|
|
Packit Service |
4684c1 |
prefix_length += 8;
|
|
Packit Service |
4684c1 |
} else {
|
|
Packit Service |
4684c1 |
switch(mask[i]) {
|
|
Packit Service |
4684c1 |
case 0xFE: prefix_length += 7; break;
|
|
Packit Service |
4684c1 |
case 0xFC: prefix_length += 6; break;
|
|
Packit Service |
4684c1 |
case 0xF8: prefix_length += 5; break;
|
|
Packit Service |
4684c1 |
case 0xF0: prefix_length += 4; break;
|
|
Packit Service |
4684c1 |
case 0xE0: prefix_length += 3; break;
|
|
Packit Service |
4684c1 |
case 0xC0: prefix_length += 2; break;
|
|
Packit Service |
4684c1 |
case 0x80: prefix_length += 1; break;
|
|
Packit Service |
4684c1 |
case 0x00: break;
|
|
Packit Service |
4684c1 |
default:
|
|
Packit Service |
4684c1 |
return -1;
|
|
Packit Service |
4684c1 |
}
|
|
Packit Service |
4684c1 |
break;
|
|
Packit Service |
4684c1 |
}
|
|
Packit Service |
4684c1 |
}
|
|
Packit Service |
4684c1 |
i++;
|
|
Packit Service |
4684c1 |
// mask is invalid, if there follows something else than 0x00
|
|
Packit Service |
4684c1 |
for ( ; i
|
|
Packit Service |
4684c1 |
if (mask[i] != 0)
|
|
Packit Service |
4684c1 |
return -1;
|
|
Packit Service |
4684c1 |
}
|
|
Packit Service |
4684c1 |
return prefix_length;
|
|
Packit Service |
4684c1 |
}
|
|
Packit Service |
4684c1 |
|
|
Packit Service |
4684c1 |
/*-
|
|
Packit Service |
4684c1 |
* _gnutls_ip_to_string:
|
|
Packit Service |
4684c1 |
* @_ip: IP address (RFC5280 format)
|
|
Packit Service |
4684c1 |
* @ip_size: Size of @_ip (4 or 16)
|
|
Packit Service |
4684c1 |
* @out: Resulting string
|
|
Packit Service |
4684c1 |
* @out_size: Size of @out
|
|
Packit Service |
4684c1 |
*
|
|
Packit Service |
4684c1 |
* Transform IP address into human-readable string.
|
|
Packit Service |
4684c1 |
* @string must be already allocated and
|
|
Packit Service |
4684c1 |
* at least 16/48 bytes for IPv4/v6 address respectively.
|
|
Packit Service |
4684c1 |
*
|
|
Packit Service |
4684c1 |
* Returns: Address of result string.
|
|
Packit Service |
4684c1 |
-*/
|
|
Packit Service |
4684c1 |
const char *_gnutls_ip_to_string(const void *_ip, unsigned int ip_size, char *out, unsigned int out_size)
|
|
Packit Service |
4684c1 |
{
|
|
Packit Service |
4684c1 |
|
|
Packit Service |
4684c1 |
if (ip_size != 4 && ip_size != 16) {
|
|
Packit Service |
4684c1 |
gnutls_assert();
|
|
Packit Service |
4684c1 |
return NULL;
|
|
Packit Service |
4684c1 |
}
|
|
Packit Service |
4684c1 |
|
|
Packit Service |
4684c1 |
if (ip_size == 4 && out_size < 16) {
|
|
Packit Service |
4684c1 |
gnutls_assert();
|
|
Packit Service |
4684c1 |
return NULL;
|
|
Packit Service |
4684c1 |
}
|
|
Packit Service |
4684c1 |
|
|
Packit Service |
4684c1 |
if (ip_size == 16 && out_size < 48) {
|
|
Packit Service |
4684c1 |
gnutls_assert();
|
|
Packit Service |
4684c1 |
return NULL;
|
|
Packit Service |
4684c1 |
}
|
|
Packit Service |
4684c1 |
|
|
Packit Service |
4684c1 |
if (ip_size == 4)
|
|
Packit Service |
4684c1 |
return inet_ntop(AF_INET, _ip, out, out_size);
|
|
Packit Service |
4684c1 |
else
|
|
Packit Service |
4684c1 |
return inet_ntop(AF_INET6, _ip, out, out_size);
|
|
Packit Service |
4684c1 |
}
|
|
Packit Service |
4684c1 |
|
|
Packit Service |
4684c1 |
/*-
|
|
Packit Service |
4684c1 |
* _gnutls_cidr_to_string:
|
|
Packit Service |
4684c1 |
* @_ip: CIDR range (RFC5280 format)
|
|
Packit Service |
4684c1 |
* @ip_size: Size of @_ip (8 or 32)
|
|
Packit Service |
4684c1 |
* @out: Resulting string
|
|
Packit Service |
4684c1 |
* @out_size: Size of @out
|
|
Packit Service |
4684c1 |
*
|
|
Packit Service |
4684c1 |
* Transform CIDR IP address range into human-readable string.
|
|
Packit Service |
4684c1 |
* The input @_ip must be in RFC5280 format (IP address in network byte
|
|
Packit Service |
4684c1 |
* order, followed by its network mask which is 4 bytes in IPv4 and
|
|
Packit Service |
4684c1 |
* 16 bytes in IPv6). @string must be already allocated and
|
|
Packit Service |
4684c1 |
* at least 33/97 bytes for IPv4/v6 address respectively.
|
|
Packit Service |
4684c1 |
*
|
|
Packit Service |
4684c1 |
* Returns: Address of result string.
|
|
Packit Service |
4684c1 |
-*/
|
|
Packit Service |
4684c1 |
const char *_gnutls_cidr_to_string(const void *_ip, unsigned int ip_size, char *out, unsigned int out_size)
|
|
Packit Service |
4684c1 |
{
|
|
Packit Service |
4684c1 |
const unsigned char *ip = _ip;
|
|
Packit Service |
4684c1 |
char tmp[64];
|
|
Packit Service |
4684c1 |
const char *p;
|
|
Packit Service |
4684c1 |
|
|
Packit Service |
4684c1 |
if (ip_size != 8 && ip_size != 32) {
|
|
Packit Service |
4684c1 |
gnutls_assert();
|
|
Packit Service |
4684c1 |
return NULL;
|
|
Packit Service |
4684c1 |
}
|
|
Packit Service |
4684c1 |
|
|
Packit Service |
4684c1 |
if (ip_size == 8) {
|
|
Packit Service |
4684c1 |
p = inet_ntop(AF_INET, ip, tmp, sizeof(tmp));
|
|
Packit Service |
4684c1 |
|
|
Packit Service |
4684c1 |
if (p)
|
|
Packit Service |
4684c1 |
snprintf(out, out_size, "%s/%d", tmp, _gnutls_mask_to_prefix(ip+4, 4));
|
|
Packit Service |
4684c1 |
} else {
|
|
Packit Service |
4684c1 |
p = inet_ntop(AF_INET6, ip, tmp, sizeof(tmp));
|
|
Packit Service |
4684c1 |
|
|
Packit Service |
4684c1 |
if (p)
|
|
Packit Service |
4684c1 |
snprintf(out, out_size, "%s/%d", tmp, _gnutls_mask_to_prefix(ip+16, 16));
|
|
Packit Service |
4684c1 |
}
|
|
Packit Service |
4684c1 |
|
|
Packit Service |
4684c1 |
if (p == NULL)
|
|
Packit Service |
4684c1 |
return NULL;
|
|
Packit Service |
4684c1 |
|
|
Packit Service |
4684c1 |
return out;
|
|
Packit Service |
4684c1 |
}
|
|
Packit Service |
4684c1 |
|
|
Packit Service |
4684c1 |
static void prefix_to_mask(unsigned prefix, unsigned char *mask, size_t mask_size)
|
|
Packit Service |
4684c1 |
{
|
|
Packit Service |
4684c1 |
int i;
|
|
Packit Service |
4684c1 |
unsigned j;
|
|
Packit Service |
4684c1 |
memset(mask, 0, mask_size);
|
|
Packit Service |
4684c1 |
|
|
Packit Service |
4684c1 |
for (i = prefix, j = 0; i > 0 && j < mask_size; i -= 8, j++) {
|
|
Packit Service |
4684c1 |
if (i >= 8) {
|
|
Packit Service |
4684c1 |
mask[j] = 0xff;
|
|
Packit Service |
4684c1 |
} else {
|
|
Packit Service |
4684c1 |
mask[j] = (unsigned long)(0xffU << (8 - i));
|
|
Packit Service |
4684c1 |
}
|
|
Packit Service |
4684c1 |
}
|
|
Packit Service |
4684c1 |
}
|
|
Packit Service |
4684c1 |
|
|
Packit Service |
4684c1 |
/*-
|
|
Packit Service |
4684c1 |
* _gnutls_mask_ip:
|
|
Packit Service |
4684c1 |
* @ip: IP of @ipsize bytes
|
|
Packit Service |
4684c1 |
* @mask: netmask of @ipsize bytes
|
|
Packit Service |
4684c1 |
* @ipsize: IP length (4 or 16)
|
|
Packit Service |
4684c1 |
*
|
|
Packit Service |
4684c1 |
* Mask given IP in place according to the given mask.
|
|
Packit Service |
4684c1 |
*
|
|
Packit Service |
4684c1 |
* Returns: On success, %GNUTLS_E_SUCCESS (0) is returned, otherwise a negative error value.
|
|
Packit Service |
4684c1 |
-*/
|
|
Packit Service |
4684c1 |
int _gnutls_mask_ip(unsigned char *ip, const unsigned char *mask, unsigned ipsize)
|
|
Packit Service |
4684c1 |
{
|
|
Packit Service |
4684c1 |
unsigned i;
|
|
Packit Service |
4684c1 |
|
|
Packit Service |
4684c1 |
if (ipsize != 4 && ipsize != 16)
|
|
Packit Service |
4684c1 |
return GNUTLS_E_MALFORMED_CIDR;
|
|
Packit Service |
4684c1 |
for (i = 0; i < ipsize; i++)
|
|
Packit Service |
4684c1 |
ip[i] &= mask[i];
|
|
Packit Service |
4684c1 |
return GNUTLS_E_SUCCESS;
|
|
Packit Service |
4684c1 |
}
|
|
Packit Service |
4684c1 |
|
|
Packit Service |
4684c1 |
/**
|
|
Packit Service |
4684c1 |
* gnutls_x509_cidr_to_rfc5280:
|
|
Packit Service |
4684c1 |
* @cidr: CIDR in RFC4632 format (IP/prefix), null-terminated
|
|
Packit Service |
4684c1 |
* @cidr_rfc5280: CIDR range converted to RFC5280 format
|
|
Packit Service |
4684c1 |
*
|
|
Packit Service |
4684c1 |
* This function will convert text CIDR range with prefix (such as '10.0.0.0/8')
|
|
Packit Service |
4684c1 |
* to RFC5280 (IP address in network byte order followed by its network mask).
|
|
Packit Service |
4684c1 |
* Works for both IPv4 and IPv6.
|
|
Packit Service |
4684c1 |
*
|
|
Packit Service |
4684c1 |
* The resulting object is directly usable for IP name constraints usage,
|
|
Packit Service |
4684c1 |
* for example in functions %gnutls_x509_name_constraints_add_permitted
|
|
Packit Service |
4684c1 |
* or %gnutls_x509_name_constraints_add_excluded.
|
|
Packit Service |
4684c1 |
*
|
|
Packit Service |
4684c1 |
* The data in datum needs to be deallocated using gnutls_free().
|
|
Packit Service |
4684c1 |
*
|
|
Packit Service |
4684c1 |
* Returns: On success, %GNUTLS_E_SUCCESS (0) is returned, otherwise a negative error value.
|
|
Packit Service |
4684c1 |
*
|
|
Packit Service |
4684c1 |
* Since: 3.5.4
|
|
Packit Service |
4684c1 |
*/
|
|
Packit Service |
4684c1 |
int gnutls_x509_cidr_to_rfc5280(const char *cidr, gnutls_datum_t *cidr_rfc5280)
|
|
Packit Service |
4684c1 |
{
|
|
Packit Service |
4684c1 |
unsigned iplength, prefix;
|
|
Packit Service |
4684c1 |
int ret;
|
|
Packit Service |
4684c1 |
char *p;
|
|
Packit Service |
4684c1 |
char *p_end = NULL;
|
|
Packit Service |
4684c1 |
char *cidr_tmp;
|
|
Packit Service |
4684c1 |
|
|
Packit Service |
4684c1 |
p = strchr(cidr, '/');
|
|
Packit Service |
4684c1 |
if (p != NULL) {
|
|
Packit Service |
4684c1 |
prefix = strtol(p+1, &p_end, 10);
|
|
Packit Service |
4684c1 |
if (prefix == 0 && p_end == p+1) {
|
|
Packit Service |
4684c1 |
_gnutls_debug_log("Cannot parse prefix given in CIDR %s\n", cidr);
|
|
Packit Service |
4684c1 |
gnutls_assert();
|
|
Packit Service |
4684c1 |
return GNUTLS_E_MALFORMED_CIDR;
|
|
Packit Service |
4684c1 |
}
|
|
Packit Service |
4684c1 |
unsigned length = p-cidr+1;
|
|
Packit Service |
4684c1 |
cidr_tmp = gnutls_malloc(length);
|
|
Packit Service |
4684c1 |
if (cidr_tmp == NULL) {
|
|
Packit Service |
4684c1 |
return gnutls_assert_val(GNUTLS_E_MEMORY_ERROR);
|
|
Packit Service |
4684c1 |
}
|
|
Packit Service |
4684c1 |
memcpy(cidr_tmp, cidr, length);
|
|
Packit Service |
4684c1 |
cidr_tmp[length-1] = 0;
|
|
Packit Service |
4684c1 |
} else {
|
|
Packit Service |
4684c1 |
_gnutls_debug_log("No prefix given in CIDR %s\n", cidr);
|
|
Packit Service |
4684c1 |
gnutls_assert();
|
|
Packit Service |
4684c1 |
return GNUTLS_E_MALFORMED_CIDR;
|
|
Packit Service |
4684c1 |
}
|
|
Packit Service |
4684c1 |
|
|
Packit Service |
4684c1 |
if (strchr(cidr, ':') != 0) { /* IPv6 */
|
|
Packit Service |
4684c1 |
iplength = 16;
|
|
Packit Service |
4684c1 |
} else { /* IPv4 */
|
|
Packit Service |
4684c1 |
iplength = 4;
|
|
Packit Service |
4684c1 |
}
|
|
Packit Service |
4684c1 |
cidr_rfc5280->size = 2*iplength;
|
|
Packit Service |
4684c1 |
|
|
Packit Service |
4684c1 |
if (prefix > iplength*8) {
|
|
Packit Service |
4684c1 |
_gnutls_debug_log("Invalid prefix given in CIDR %s (%d)\n", cidr, prefix);
|
|
Packit Service |
4684c1 |
ret = gnutls_assert_val(GNUTLS_E_MALFORMED_CIDR);
|
|
Packit Service |
4684c1 |
goto cleanup;
|
|
Packit Service |
4684c1 |
}
|
|
Packit Service |
4684c1 |
|
|
Packit Service |
4684c1 |
cidr_rfc5280->data = gnutls_malloc(cidr_rfc5280->size);
|
|
Packit Service |
4684c1 |
if (cidr_rfc5280->data == NULL) {
|
|
Packit Service |
4684c1 |
ret = gnutls_assert_val(GNUTLS_E_MEMORY_ERROR);
|
|
Packit Service |
4684c1 |
goto cleanup;
|
|
Packit Service |
4684c1 |
}
|
|
Packit Service |
4684c1 |
|
|
Packit Service |
4684c1 |
ret = inet_pton(iplength == 4 ? AF_INET : AF_INET6, cidr_tmp, cidr_rfc5280->data);
|
|
Packit Service |
4684c1 |
if (ret == 0) {
|
|
Packit Service |
4684c1 |
_gnutls_debug_log("Cannot parse IP from CIDR %s\n", cidr_tmp);
|
|
Packit Service |
4684c1 |
ret = gnutls_assert_val(GNUTLS_E_MALFORMED_CIDR);
|
|
Packit Service |
4684c1 |
goto cleanup;
|
|
Packit Service |
4684c1 |
}
|
|
Packit Service |
4684c1 |
|
|
Packit Service |
4684c1 |
prefix_to_mask(prefix, &cidr_rfc5280->data[iplength], iplength);
|
|
Packit Service |
4684c1 |
_gnutls_mask_ip(cidr_rfc5280->data, &cidr_rfc5280->data[iplength], iplength);
|
|
Packit Service |
4684c1 |
|
|
Packit Service |
4684c1 |
ret = GNUTLS_E_SUCCESS;
|
|
Packit Service |
4684c1 |
|
|
Packit Service |
4684c1 |
cleanup:
|
|
Packit Service |
4684c1 |
gnutls_free(cidr_tmp);
|
|
Packit Service |
4684c1 |
return ret;
|
|
Packit Service |
4684c1 |
}
|