Resolve merge conflict

This commit is contained in:
Guido Vranken 2017-08-13 03:42:02 +02:00
commit 6c178b43a3
64 changed files with 386 additions and 2086 deletions

View file

@ -14,11 +14,11 @@ env:
- PREFIX="${HOME}/opt"
- TAP_WINDOWS_VERSION=9.21.2
- LZO_VERSION=2.10
- PKCS11_HELPER_VERSION=1.11
- MBEDTLS_VERSION="2.4.0"
- PKCS11_HELPER_VERSION=1.22
- MBEDTLS_VERSION="2.5.1"
- MBEDTLS_CFLAGS="-I${PREFIX}/include"
- MBEDTLS_LIBS="-L${PREFIX}/lib -lmbedtls -lmbedx509 -lmbedcrypto"
- OPENSSL_VERSION="1.0.2k"
- OPENSSL_VERSION="1.0.2l"
- OPENSSL_CFLAGS="-I${PREFIX}/include"
- OPENSSL_LIBS="-L${PREFIX}/lib -lssl -lcrypto"

View file

@ -35,7 +35,7 @@ build_lzo () {
download_pkcs11_helper () {
if [ ! -f "pkcs11-helper-${PKCS11_HELPER_VERSION}.tar.bz2" ]; then
wget -P download-cache/ \
"http://downloads.sourceforge.net/project/opensc/pkcs11-helper/pkcs11-helper-${PKCS11_HELPER_VERSION}.tar.bz2"
"https://github.com/OpenSC/pkcs11-helper/releases/download/pkcs11-helper-${PKCS11_HELPER_VERSION}/pkcs11-helper-${PKCS11_HELPER_VERSION}.tar.bz2"
fi
}
@ -46,7 +46,11 @@ build_pkcs11_helper () {
cd "pkcs11-helper-${PKCS11_HELPER_VERSION}"
./configure --host=${CHOST} --program-prefix='' --libdir=${PREFIX}/lib \
--prefix=${PREFIX} --build=x86_64-pc-linux-gnu --disable-crypto-engine-gnutls --disable-crypto-engine-nss
--prefix=${PREFIX} --build=x86_64-pc-linux-gnu \
--disable-crypto-engine-gnutls \
--disable-crypto-engine-nss \
--disable-crypto-engine-polarssl \
--disable-crypto-engine-mbedtls
make all install
)
echo "${PKCS11_HELPER_VERSION}" > "${PREFIX}/.pkcs11_helper-version"

View file

@ -44,6 +44,13 @@ ECDH key exchange
The TLS control channel now supports for elliptic curve diffie-hellmann
key exchange (ECDH).
Improved Certificate Revocation List (CRL) processing
CRLs are now handled by the crypto library (OpenSSL or mbed TLS), instead
of inside OpenVPN itself. The crypto library implementations are more
strict than the OpenVPN implementation was. This might reject peer
certificates that would previously be accepted. If this occurs, OpenVPN
will log the crypto library's error description.
Dualstack round-robin DNS client connect
Instead of only using the first address of each ``--remote`` OpenVPN
will now try all addresses (IPv6 and IPv4) of a ``--remote`` entry.
@ -160,12 +167,6 @@ Deprecated features
will then use ``--key-method 2`` by default. Note that this requires changing
the option in both the client and server side configs.
- CRLs are now handled by the crypto library (OpenSSL or mbed TLS), instead of
inside OpenVPN itself. The crypto library implementations are more strict
than the OpenVPN implementation was. This might reject peer certificates
that would previously be accepted. If this occurs, OpenVPN will log the
crypto library's error description.
- ``--tls-remote`` is removed in 2.4, as indicated in the 2.3 man-pages. Similar
functionality is provided via ``--verify-x509-name``, which does the same job in
a better way.

View file

@ -668,7 +668,7 @@ AC_FUNC_FORK
AC_CHECK_FUNCS([ \
daemon chroot getpwnam setuid nice system getpid dup dup2 \
getpass strerror syslog openlog mlockall getgrnam setgid \
getpass syslog openlog mlockall getgrnam setgid \
setgroups stat flock readv writev time gettimeofday \
ctime memset vsnprintf strdup \
setsid chdir putenv getpeername unlink \
@ -925,8 +925,6 @@ if test "${enable_crypto}" = "yes" -a "${with_crypto_library}" = "openssl"; then
AC_CHECK_FUNCS(
[ \
EVP_CIPHER_CTX_new \
EVP_CIPHER_CTX_free \
HMAC_CTX_new \
HMAC_CTX_free \
HMAC_CTX_reset \
@ -942,6 +940,7 @@ if test "${enable_crypto}" = "yes" -a "${with_crypto_library}" = "openssl"; then
EVP_PKEY_id \
EVP_PKEY_get0_RSA \
EVP_PKEY_get0_DSA \
EVP_PKEY_get0_EC_KEY \
RSA_set_flags \
RSA_bits \
RSA_get0_key \
@ -957,6 +956,7 @@ if test "${enable_crypto}" = "yes" -a "${with_crypto_library}" = "openssl"; then
RSA_meth_set_init \
RSA_meth_set_finish \
RSA_meth_set0_app_data \
EC_GROUP_order_bits
]
)

View file

@ -1,13 +0,0 @@
CFILES = cert_data.c common_osx.c crypto_osx.c main.c
OFILES = $(CFILES:.c=.o) ../../src/openvpn/base64.o
prog = keychain-mcd
CC = gcc
CFLAGS = -Wall
LDFLAGS = -framework CoreFoundation -framework Security -framework CoreServices
$(prog): $(OFILES)
$(CC) $(LDFLAGS) $(OFILES) -o $(prog)
%.o: %.c
$(CC) $(CFLAGS) -c $< -o $@

View file

@ -1,866 +0,0 @@
/*
* OpenVPN -- An application to securely tunnel IP networks
* over a single UDP port, with support for SSL/TLS-based
* session authentication and key exchange,
* packet encryption, packet authentication, and
* packet compression.
*
* Copyright (C) 2010 Brian Raderman <brian@irregularexpression.org>
* Copyright (C) 2013-2015 Vasily Kulikov <segoon@openwall.com>
*
* This program is free software; you can redistribute it and/or modify
* it under the terms of the GNU General Public License version 2
* as published by the Free Software Foundation.
*
* This program is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
* GNU General Public License for more details.
*
* You should have received a copy of the GNU General Public License along
* with this program; if not, write to the Free Software Foundation, Inc.,
* 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA.
*/
#include "cert_data.h"
#include <CommonCrypto/CommonDigest.h>
#include <openssl/ssl.h>
#include "common_osx.h"
#include "crypto_osx.h"
#include <err.h>
CFStringRef kCertDataSubjectName = CFSTR("subject"),
kCertDataIssuerName = CFSTR("issuer"),
kCertDataSha1Name = CFSTR("SHA1"),
kCertDataMd5Name = CFSTR("MD5"),
kCertDataSerialName = CFSTR("serial"),
kCertNameFwdSlash = CFSTR("/"),
kCertNameEquals = CFSTR("=");
CFStringRef kCertNameOrganization = CFSTR("o"),
kCertNameOrganizationalUnit = CFSTR("ou"),
kCertNameCountry = CFSTR("c"),
kCertNameLocality = CFSTR("l"),
kCertNameState = CFSTR("st"),
kCertNameCommonName = CFSTR("cn"),
kCertNameEmail = CFSTR("e");
CFStringRef kStringSpace = CFSTR(" "),
kStringEmpty = CFSTR("");
typedef struct _CertName
{
CFArrayRef countryName, organization, organizationalUnit, commonName, description, emailAddress,
stateName, localityName;
} CertName, *CertNameRef;
typedef struct _DescData
{
CFStringRef name, value;
} DescData, *DescDataRef;
void destroyDescData(DescDataRef pData);
CertNameRef
createCertName()
{
CertNameRef pCertName = (CertNameRef)malloc(sizeof(CertName));
pCertName->countryName = CFArrayCreateMutable(NULL, 0, &kCFTypeArrayCallBacks);
pCertName->organization = CFArrayCreateMutable(NULL, 0, &kCFTypeArrayCallBacks);
pCertName->organizationalUnit = CFArrayCreateMutable(NULL, 0, &kCFTypeArrayCallBacks);
pCertName->commonName = CFArrayCreateMutable(NULL, 0, &kCFTypeArrayCallBacks);
pCertName->description = CFArrayCreateMutable(NULL, 0, &kCFTypeArrayCallBacks);
pCertName->emailAddress = CFArrayCreateMutable(NULL, 0, &kCFTypeArrayCallBacks);
pCertName->stateName = CFArrayCreateMutable(NULL, 0, &kCFTypeArrayCallBacks);
pCertName->localityName = CFArrayCreateMutable(NULL, 0, &kCFTypeArrayCallBacks);
return pCertName;
}
void
destroyCertName(CertNameRef pCertName)
{
if (!pCertName)
{
return;
}
CFRelease(pCertName->countryName);
CFRelease(pCertName->organization);
CFRelease(pCertName->organizationalUnit);
CFRelease(pCertName->commonName);
CFRelease(pCertName->description);
CFRelease(pCertName->emailAddress);
CFRelease(pCertName->stateName);
CFRelease(pCertName->localityName);
free(pCertName);
}
bool
CFStringRefCmpCString(CFStringRef cfstr, const char *str)
{
CFStringRef tmp = CFStringCreateWithCStringNoCopy(NULL, str, kCFStringEncodingUTF8, kCFAllocatorNull);
CFComparisonResult cresult = CFStringCompare(cfstr, tmp, 0);
bool result = cresult == kCFCompareEqualTo;
CFRelease(tmp);
return result;
}
CFDateRef
GetDateFieldFromCertificate(SecCertificateRef certificate, CFTypeRef oid)
{
const void *keys[] = { oid };
CFDictionaryRef dict = NULL;
CFErrorRef error;
CFDateRef date = NULL;
CFArrayRef keySelection = CFArrayCreate(NULL, keys, sizeof(keys)/sizeof(keys[0]), &kCFTypeArrayCallBacks);
dict = SecCertificateCopyValues(certificate, keySelection, &error);
if (dict == NULL)
{
printErrorMsg("GetDateFieldFromCertificate: SecCertificateCopyValues", error);
goto release_ks;
}
CFDictionaryRef vals = dict ? CFDictionaryGetValue(dict, oid) : NULL;
CFNumberRef vals2 = vals ? CFDictionaryGetValue(vals, kSecPropertyKeyValue) : NULL;
if (vals2 == NULL)
{
goto release_dict;
}
CFAbsoluteTime validityNotBefore;
if (CFNumberGetValue(vals2, kCFNumberDoubleType, &validityNotBefore))
{
date = CFDateCreate(kCFAllocatorDefault,validityNotBefore);
}
release_dict:
CFRelease(dict);
release_ks:
CFRelease(keySelection);
return date;
}
CFArrayRef
GetFieldsFromCertificate(SecCertificateRef certificate, CFTypeRef oid)
{
CFMutableArrayRef fields = CFArrayCreateMutable(NULL, 0, NULL);
CertNameRef pCertName = createCertName();
const void *keys[] = { oid, };
CFDictionaryRef dict;
CFErrorRef error;
CFArrayRef keySelection = CFArrayCreate(NULL, keys, 1, NULL);
dict = SecCertificateCopyValues(certificate, keySelection, &error);
if (dict == NULL)
{
printErrorMsg("GetFieldsFromCertificate: SecCertificateCopyValues", error);
CFRelease(keySelection);
CFRelease(fields);
destroyCertName(pCertName);
return NULL;
}
CFDictionaryRef vals = CFDictionaryGetValue(dict, oid);
CFArrayRef vals2 = vals ? CFDictionaryGetValue(vals, kSecPropertyKeyValue) : NULL;
if (vals2)
{
for (int i = 0; i < CFArrayGetCount(vals2); i++) {
CFDictionaryRef subDict = CFArrayGetValueAtIndex(vals2, i);
CFStringRef label = CFDictionaryGetValue(subDict, kSecPropertyKeyLabel);
CFStringRef value = CFDictionaryGetValue(subDict, kSecPropertyKeyValue);
if (CFStringCompare(label, kSecOIDEmailAddress, 0) == kCFCompareEqualTo)
{
CFArrayAppendValue((CFMutableArrayRef)pCertName->emailAddress, value);
}
else if (CFStringCompare(label, kSecOIDCountryName, 0) == kCFCompareEqualTo)
{
CFArrayAppendValue((CFMutableArrayRef)pCertName->countryName, value);
}
else if (CFStringCompare(label, kSecOIDOrganizationName, 0) == kCFCompareEqualTo)
{
CFArrayAppendValue((CFMutableArrayRef)pCertName->organization, value);
}
else if (CFStringCompare(label, kSecOIDOrganizationalUnitName, 0) == kCFCompareEqualTo)
{
CFArrayAppendValue((CFMutableArrayRef)pCertName->organizationalUnit, value);
}
else if (CFStringCompare(label, kSecOIDCommonName, 0) == kCFCompareEqualTo)
{
CFArrayAppendValue((CFMutableArrayRef)pCertName->commonName, value);
}
else if (CFStringCompare(label, kSecOIDDescription, 0) == kCFCompareEqualTo)
{
CFArrayAppendValue((CFMutableArrayRef)pCertName->description, value);
}
else if (CFStringCompare(label, kSecOIDStateProvinceName, 0) == kCFCompareEqualTo)
{
CFArrayAppendValue((CFMutableArrayRef)pCertName->stateName, value);
}
else if (CFStringCompare(label, kSecOIDLocalityName, 0) == kCFCompareEqualTo)
{
CFArrayAppendValue((CFMutableArrayRef)pCertName->localityName, value);
}
}
CFArrayAppendValue(fields, pCertName);
}
CFRelease(dict);
CFRelease(keySelection);
return fields;
}
CertDataRef
createCertDataFromCertificate(SecCertificateRef certificate)
{
CertDataRef pCertData = (CertDataRef)malloc(sizeof(CertData));
pCertData->subject = GetFieldsFromCertificate(certificate, kSecOIDX509V1SubjectName);
pCertData->issuer = GetFieldsFromCertificate(certificate, kSecOIDX509V1IssuerName);
CFDataRef data = SecCertificateCopyData(certificate);
if (data == NULL)
{
warnx("SecCertificateCopyData() returned NULL");
destroyCertData(pCertData);
return NULL;
}
unsigned char sha1[CC_SHA1_DIGEST_LENGTH];
CC_SHA1(CFDataGetBytePtr(data), CFDataGetLength(data), sha1);
pCertData->sha1 = createHexString(sha1, CC_SHA1_DIGEST_LENGTH);
unsigned char md5[CC_MD5_DIGEST_LENGTH];
CC_MD5(CFDataGetBytePtr(data), CFDataGetLength(data), md5);
pCertData->md5 = createHexString((unsigned char *)md5, CC_MD5_DIGEST_LENGTH);
CFDataRef serial = SecCertificateCopySerialNumber(certificate, NULL);
pCertData->serial = createHexString((unsigned char *)CFDataGetBytePtr(serial), CFDataGetLength(serial));
CFRelease(serial);
return pCertData;
}
CFStringRef
stringFromRange(const char *cstring, CFRange range)
{
CFStringRef str = CFStringCreateWithBytes(NULL, (uint8 *)&cstring[range.location], range.length, kCFStringEncodingUTF8, false);
CFMutableStringRef mutableStr = CFStringCreateMutableCopy(NULL, 0, str);
CFStringTrimWhitespace(mutableStr);
CFRelease(str);
return mutableStr;
}
DescDataRef
createDescData(const char *description, CFRange nameRange, CFRange valueRange)
{
DescDataRef pRetVal = (DescDataRef)malloc(sizeof(DescData));
memset(pRetVal, 0, sizeof(DescData));
if (nameRange.length > 0)
{
pRetVal->name = stringFromRange(description, nameRange);
}
if (valueRange.length > 0)
{
pRetVal->value = stringFromRange(description, valueRange);
}
#if 0
fprintf(stderr, "name = '%s', value = '%s'\n",
CFStringGetCStringPtr(pRetVal->name, kCFStringEncodingUTF8),
CFStringGetCStringPtr(pRetVal->value, kCFStringEncodingUTF8));
#endif
return pRetVal;
}
void
destroyDescData(DescDataRef pData)
{
if (pData->name)
{
CFRelease(pData->name);
}
if (pData->value)
{
CFRelease(pData->value);
}
free(pData);
}
CFArrayRef
createDescDataPairs(const char *description)
{
int numChars = strlen(description);
CFRange nameRange, valueRange;
DescDataRef pData;
CFMutableArrayRef retVal = CFArrayCreateMutable(NULL, 0, NULL);
int i = 0;
nameRange = CFRangeMake(0, 0);
valueRange = CFRangeMake(0, 0);
bool bInValue = false;
while (i < numChars)
{
if (!bInValue && (description[i] != ':'))
{
nameRange.length++;
}
else if (bInValue && (description[i] != ':'))
{
valueRange.length++;
}
else if (!bInValue)
{
bInValue = true;
valueRange.location = i + 1;
valueRange.length = 0;
}
else /*(bInValue) */
{
bInValue = false;
while (description[i] != ' ')
{
valueRange.length--;
i--;
}
pData = createDescData(description, nameRange, valueRange);
CFArrayAppendValue(retVal, pData);
nameRange.location = i + 1;
nameRange.length = 0;
}
i++;
}
pData = createDescData(description, nameRange, valueRange);
CFArrayAppendValue(retVal, pData);
return retVal;
}
void
arrayDestroyDescData(const void *val, void *context)
{
DescDataRef pData = (DescDataRef) val;
destroyDescData(pData);
}
int
parseNameComponent(CFStringRef dn, CFStringRef *pName, CFStringRef *pValue)
{
CFArrayRef nameStrings = CFStringCreateArrayBySeparatingStrings(NULL, dn, kCertNameEquals);
*pName = *pValue = NULL;
if (CFArrayGetCount(nameStrings) != 2)
{
return 0;
}
CFMutableStringRef str;
str = CFStringCreateMutableCopy(NULL, 0, CFArrayGetValueAtIndex(nameStrings, 0));
CFStringTrimWhitespace(str);
*pName = str;
str = CFStringCreateMutableCopy(NULL, 0, CFArrayGetValueAtIndex(nameStrings, 1));
CFStringTrimWhitespace(str);
*pValue = str;
CFRelease(nameStrings);
return 1;
}
int
tryAppendSingleCertField(CertNameRef pCertName, CFArrayRef where, CFStringRef key,
CFStringRef name, CFStringRef value)
{
if (CFStringCompareWithOptions(name, key, CFRangeMake(0, CFStringGetLength(name)), kCFCompareCaseInsensitive)
== kCFCompareEqualTo)
{
CFArrayAppendValue((CFMutableArrayRef)where, value);
return 1;
}
return 0;
}
int
appendCertField(CertNameRef pCert, CFStringRef name, CFStringRef value)
{
struct {
CFArrayRef field;
CFStringRef key;
} fields[] = {
{ pCert->organization, kCertNameOrganization},
{ pCert->organizationalUnit, kCertNameOrganizationalUnit},
{ pCert->countryName, kCertNameCountry},
{ pCert->localityName, kCertNameLocality},
{ pCert->stateName, kCertNameState},
{ pCert->commonName, kCertNameCommonName},
{ pCert->emailAddress, kCertNameEmail},
};
int i;
int ret = 0;
for (i = 0; i<sizeof(fields)/sizeof(fields[0]); i++)
ret += tryAppendSingleCertField(pCert, fields[i].field, fields[i].key, name, value);
return ret;
}
int
parseCertName(CFStringRef nameDesc, CFMutableArrayRef names)
{
CFArrayRef nameStrings = CFStringCreateArrayBySeparatingStrings(NULL, nameDesc, kCertNameFwdSlash);
int count = CFArrayGetCount(nameStrings);
int i;
int ret = 1;
CertNameRef pCertName = createCertName();
for (i = 0; i < count; i++)
{
CFMutableStringRef dn = CFStringCreateMutableCopy(NULL, 0, CFArrayGetValueAtIndex(nameStrings, i));
CFStringTrimWhitespace(dn);
CFStringRef name, value;
if (!parseNameComponent(dn, &name, &value))
{
ret = 0;
}
if (!name || !value)
{
if (name)
{
CFRelease(name);
}
if (value)
{
CFRelease(value);
}
if (name && !value)
{
ret = 0;
}
CFRelease(dn);
continue;
}
if (!appendCertField(pCertName, name, value))
{
ret = 0;
}
CFRelease(name);
CFRelease(value);
CFRelease(dn);
}
CFArrayAppendValue(names, pCertName);
CFRelease(nameStrings);
return ret;
}
int
arrayParseDescDataPair(const void *val, void *context)
{
DescDataRef pDescData = (DescDataRef)val;
CertDataRef pCertData = (CertDataRef)context;
int ret = 1;
if (!pDescData->name || !pDescData->value)
{
return 0;
}
if (CFStringCompareWithOptions(pDescData->name, kCertDataSubjectName, CFRangeMake(0, CFStringGetLength(pDescData->name)), kCFCompareCaseInsensitive) == kCFCompareEqualTo)
{
ret = parseCertName(pDescData->value, (CFMutableArrayRef)pCertData->subject);
}
else if (CFStringCompareWithOptions(pDescData->name, kCertDataIssuerName, CFRangeMake(0, CFStringGetLength(pDescData->name)), kCFCompareCaseInsensitive) == kCFCompareEqualTo)
{
ret = parseCertName(pDescData->value, (CFMutableArrayRef)pCertData->issuer);
}
else if (CFStringCompareWithOptions(pDescData->name, kCertDataSha1Name, CFRangeMake(0, CFStringGetLength(pDescData->name)), kCFCompareCaseInsensitive) == kCFCompareEqualTo)
{
pCertData->sha1 = CFRetain(pDescData->value);
}
else if (CFStringCompareWithOptions(pDescData->name, kCertDataMd5Name, CFRangeMake(0, CFStringGetLength(pDescData->name)), kCFCompareCaseInsensitive) == kCFCompareEqualTo)
{
pCertData->md5 = CFRetain(pDescData->value);
}
else if (CFStringCompareWithOptions(pDescData->name, kCertDataSerialName, CFRangeMake(0, CFStringGetLength(pDescData->name)), kCFCompareCaseInsensitive) == kCFCompareEqualTo)
{
pCertData->serial = CFRetain(pDescData->value);
}
else
{
return 0;
}
return ret;
}
CertDataRef
createCertDataFromString(const char *description)
{
CertDataRef pCertData = (CertDataRef)malloc(sizeof(CertData));
pCertData->subject = CFArrayCreateMutable(NULL, 0, NULL);
pCertData->issuer = CFArrayCreateMutable(NULL, 0, NULL);
pCertData->sha1 = NULL;
pCertData->md5 = NULL;
pCertData->serial = NULL;
CFArrayRef pairs = createDescDataPairs(description);
for (int i = 0; i<CFArrayGetCount(pairs); i++)
if (!arrayParseDescDataPair(CFArrayGetValueAtIndex(pairs, i), pCertData))
{
arrayDestroyDescData(pCertData, NULL);
CFArrayApplyFunction(pairs, CFRangeMake(0, CFArrayGetCount(pairs)), arrayDestroyDescData, NULL);
CFRelease(pairs);
return 0;
}
CFArrayApplyFunction(pairs, CFRangeMake(0, CFArrayGetCount(pairs)), arrayDestroyDescData, NULL);
CFRelease(pairs);
return pCertData;
}
void
arrayDestroyCertName(const void *val, void *context)
{
CertNameRef pCertName = (CertNameRef)val;
destroyCertName(pCertName);
}
void
destroyCertData(CertDataRef pCertData)
{
if (pCertData->subject)
{
CFArrayApplyFunction(pCertData->subject, CFRangeMake(0, CFArrayGetCount(pCertData->subject)), arrayDestroyCertName, NULL);
CFRelease(pCertData->subject);
}
if (pCertData->issuer)
{
CFArrayApplyFunction(pCertData->issuer, CFRangeMake(0, CFArrayGetCount(pCertData->issuer)), arrayDestroyCertName, NULL);
CFRelease(pCertData->issuer);
}
if (pCertData->sha1)
{
CFRelease(pCertData->sha1);
}
if (pCertData->md5)
{
CFRelease(pCertData->md5);
}
if (pCertData->serial)
{
CFRelease(pCertData->serial);
}
free(pCertData);
}
bool
stringArrayMatchesTemplate(CFArrayRef strings, CFArrayRef templateArray)
{
int templateCount, stringCount, i;
templateCount = CFArrayGetCount(templateArray);
if (templateCount > 0)
{
stringCount = CFArrayGetCount(strings);
if (stringCount != templateCount)
{
return false;
}
for (i = 0; i < stringCount; i++)
{
CFStringRef str, template;
template = (CFStringRef)CFArrayGetValueAtIndex(templateArray, i);
str = (CFStringRef)CFArrayGetValueAtIndex(strings, i);
if (CFStringCompareWithOptions(template, str, CFRangeMake(0, CFStringGetLength(template)), kCFCompareCaseInsensitive) != kCFCompareEqualTo)
{
return false;
}
}
}
return true;
}
bool
certNameMatchesTemplate(CertNameRef pCertName, CertNameRef pTemplate)
{
if (!stringArrayMatchesTemplate(pCertName->countryName, pTemplate->countryName))
{
return false;
}
else if (!stringArrayMatchesTemplate(pCertName->organization, pTemplate->organization))
{
return false;
}
else if (!stringArrayMatchesTemplate(pCertName->organizationalUnit, pTemplate->organizationalUnit))
{
return false;
}
else if (!stringArrayMatchesTemplate(pCertName->commonName, pTemplate->commonName))
{
return false;
}
else if (!stringArrayMatchesTemplate(pCertName->emailAddress, pTemplate->emailAddress))
{
return false;
}
else if (!stringArrayMatchesTemplate(pCertName->stateName, pTemplate->stateName))
{
return false;
}
else if (!stringArrayMatchesTemplate(pCertName->localityName, pTemplate->localityName))
{
return false;
}
else
{
return true;
}
}
bool
certNameArrayMatchesTemplate(CFArrayRef certNameArray, CFArrayRef templateArray)
{
int templateCount, certCount, i;
templateCount = CFArrayGetCount(templateArray);
if (templateCount > 0)
{
certCount = CFArrayGetCount(certNameArray);
if (certCount != templateCount)
{
return false;
}
for (i = 0; i < certCount; i++)
{
CertNameRef pName, pTemplateName;
pTemplateName = (CertNameRef)CFArrayGetValueAtIndex(templateArray, i);
pName = (CertNameRef)CFArrayGetValueAtIndex(certNameArray, i);
if (!certNameMatchesTemplate(pName, pTemplateName))
{
return false;
}
}
}
return true;
}
bool
hexStringMatchesTemplate(CFStringRef str, CFStringRef template)
{
if (template)
{
if (!str)
{
return false;
}
CFMutableStringRef strMutable, templateMutable;
strMutable = CFStringCreateMutableCopy(NULL, 0, str);
templateMutable = CFStringCreateMutableCopy(NULL, 0, template);
CFStringFindAndReplace(strMutable, kStringSpace, kStringEmpty, CFRangeMake(0, CFStringGetLength(strMutable)), 0);
CFStringFindAndReplace(templateMutable, kStringSpace, kStringEmpty, CFRangeMake(0, CFStringGetLength(templateMutable)), 0);
CFComparisonResult result = CFStringCompareWithOptions(templateMutable, strMutable, CFRangeMake(0, CFStringGetLength(templateMutable)), kCFCompareCaseInsensitive);
CFRelease(strMutable);
CFRelease(templateMutable);
if (result != kCFCompareEqualTo)
{
return false;
}
}
return true;
}
bool
certDataMatchesTemplate(CertDataRef pCertData, CertDataRef pTemplate)
{
if (!certNameArrayMatchesTemplate(pCertData->subject, pTemplate->subject))
{
return false;
}
if (!certNameArrayMatchesTemplate(pCertData->issuer, pTemplate->issuer))
{
return false;
}
if (!hexStringMatchesTemplate(pCertData->sha1, pTemplate->sha1))
{
return false;
}
if (!hexStringMatchesTemplate(pCertData->md5, pTemplate->md5))
{
return false;
}
if (!hexStringMatchesTemplate(pCertData->serial, pTemplate->serial))
{
return false;
}
return true;
}
bool
certExpired(SecCertificateRef certificate)
{
bool result;
CFDateRef notAfter = GetDateFieldFromCertificate(certificate, kSecOIDX509V1ValidityNotAfter);
CFDateRef notBefore = GetDateFieldFromCertificate(certificate, kSecOIDX509V1ValidityNotBefore);
CFDateRef now = CFDateCreate(kCFAllocatorDefault, CFAbsoluteTimeGetCurrent());
if (!notAfter || !notBefore || !now)
{
warnx("GetDateFieldFromCertificate() returned NULL");
result = true;
}
else
{
if (CFDateCompare(notBefore, now, NULL) != kCFCompareLessThan
|| CFDateCompare(now, notAfter, NULL) != kCFCompareLessThan)
{
result = true;
}
else
{
result = false;
}
}
CFRelease(notAfter);
CFRelease(notBefore);
CFRelease(now);
return result;
}
SecIdentityRef
findIdentity(CertDataRef pCertDataTemplate)
{
const void *keys[] = {
kSecClass,
kSecReturnRef,
kSecMatchLimit
};
const void *values[] = {
kSecClassIdentity,
kCFBooleanTrue,
kSecMatchLimitAll
};
CFArrayRef result = NULL;
CFDictionaryRef query = CFDictionaryCreate(NULL, keys, values,
sizeof(keys) / sizeof(*keys),
&kCFTypeDictionaryKeyCallBacks,
&kCFTypeDictionaryValueCallBacks);
OSStatus status = SecItemCopyMatching(query, (CFTypeRef *)&result);
CFRelease(query);
if (status != noErr)
{
warnx("No identities in keychain found");
return NULL;
}
SecIdentityRef bestIdentity = NULL;
CFDateRef bestNotBeforeDate = NULL;
for (int i = 0; i<CFArrayGetCount(result); i++)
{
SecIdentityRef identity = (SecIdentityRef)CFArrayGetValueAtIndex(result, i);
if (identity == NULL)
{
warnx("identity == NULL");
continue;
}
SecCertificateRef certificate = NULL;
SecIdentityCopyCertificate(identity, &certificate);
if (certificate == NULL)
{
warnx("SecIdentityCopyCertificate() returned NULL");
continue;
}
CertDataRef pCertData2 = createCertDataFromCertificate(certificate);
if (pCertData2 == NULL)
{
warnx("createCertDataFromCertificate() returned NULL");
goto release_cert;
}
bool bMatches = certDataMatchesTemplate(pCertData2, pCertDataTemplate);
bool bExpired = certExpired(certificate);
destroyCertData(pCertData2);
if (bMatches && !bExpired)
{
CFDateRef notBeforeDate = GetDateFieldFromCertificate(certificate, kSecOIDX509V1ValidityNotBefore);
if (!notBeforeDate)
{
warnx("GetDateFieldFromCertificate() returned NULL");
goto release_cert;
}
if (bestIdentity == NULL)
{
CFRetain(identity);
bestIdentity = identity;
bestNotBeforeDate = notBeforeDate;
CFRetain(notBeforeDate);
}
else if (CFDateCompare(bestNotBeforeDate, notBeforeDate, NULL) == kCFCompareLessThan)
{
CFRelease(bestIdentity);
CFRetain(identity);
bestIdentity = identity;
bestNotBeforeDate = notBeforeDate;
CFRetain(notBeforeDate);
}
CFRelease(notBeforeDate);
}
release_cert:
CFRelease(certificate);
}
CFRelease(result);
return bestIdentity;
}

View file

@ -1,50 +0,0 @@
/*
* OpenVPN -- An application to securely tunnel IP networks
* over a single UDP port, with support for SSL/TLS-based
* session authentication and key exchange,
* packet encryption, packet authentication, and
* packet compression.
*
* Copyright (C) 2010 Brian Raderman <brian@irregularexpression.org>
* Copyright (C) 2013-2015 Vasily Kulikov <segoon@openwall.com>
*
* This program is free software; you can redistribute it and/or modify
* it under the terms of the GNU General Public License version 2
* as published by the Free Software Foundation.
*
* This program is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
* GNU General Public License for more details.
*
* You should have received a copy of the GNU General Public License along
* with this program; if not, write to the Free Software Foundation, Inc.,
* 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA.
*/
#ifndef __cert_data_h__
#define __cert_data_h__
#include <CoreFoundation/CoreFoundation.h>
#include <Security/Security.h>
typedef struct _CertData
{
CFArrayRef subject;
CFArrayRef issuer;
CFStringRef serial;
CFStringRef md5, sha1;
} CertData, *CertDataRef;
CertDataRef createCertDataFromCertificate(SecCertificateRef certificate);
CertDataRef createCertDataFromString(const char *description);
void destroyCertData(CertDataRef pCertData);
bool certDataMatchesTemplate(CertDataRef pCertData, CertDataRef pTemplate);
void printCertData(CertDataRef pCertData);
SecIdentityRef findIdentity(CertDataRef pCertDataTemplate);
#endif /* ifndef __cert_data_h__ */

View file

@ -1,100 +0,0 @@
/*
* OpenVPN -- An application to securely tunnel IP networks
* over a single UDP port, with support for SSL/TLS-based
* session authentication and key exchange,
* packet encryption, packet authentication, and
* packet compression.
*
* Copyright (C) 2010 Brian Raderman <brian@irregularexpression.org>
* Copyright (C) 2013-2015 Vasily Kulikov <segoon@openwall.com>
*
* This program is free software; you can redistribute it and/or modify
* it under the terms of the GNU General Public License version 2
* as published by the Free Software Foundation.
*
* This program is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
* GNU General Public License for more details.
*
* You should have received a copy of the GNU General Public License along
* with this program; if not, write to the Free Software Foundation, Inc.,
* 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA.
*/
/*
#include "config.h"
#include "syshead.h"
#include "common.h"
#include "buffer.h"
#include "error.h"
*/
#include "common_osx.h"
#include <err.h>
void
printCFString(CFStringRef str)
{
CFIndex bufferLength = CFStringGetLength(str) + 1;
char *pBuffer = (char *)malloc(sizeof(char) * bufferLength);
CFStringGetCString(str, pBuffer, bufferLength, kCFStringEncodingUTF8);
warnx("%s\n", pBuffer);
free(pBuffer);
}
char *
cfstringToCstr(CFStringRef str)
{
CFIndex bufferLength = CFStringGetLength(str) + 1;
char *pBuffer = (char *)malloc(sizeof(char) * bufferLength);
CFStringGetCString(str, pBuffer, bufferLength, kCFStringEncodingUTF8);
return pBuffer;
}
void
appendHexChar(CFMutableStringRef str, unsigned char halfByte)
{
if (halfByte < 10)
{
CFStringAppendFormat(str, NULL, CFSTR("%d"), halfByte);
}
else
{
char tmp[2] = {'A'+halfByte-10, 0};
CFStringAppendCString(str, tmp, kCFStringEncodingUTF8);
}
}
CFStringRef
createHexString(unsigned char *pData, int length)
{
unsigned char byte, low, high;
int i;
CFMutableStringRef str = CFStringCreateMutable(NULL, 0);
for (i = 0; i < length; i++)
{
byte = pData[i];
low = byte & 0x0F;
high = (byte >> 4);
appendHexChar(str, high);
appendHexChar(str, low);
if (i != (length - 1))
{
CFStringAppendCString(str, " ", kCFStringEncodingUTF8);
}
}
return str;
}
void
printHex(unsigned char *pData, int length)
{
CFStringRef hexStr = createHexString(pData, length);
printCFString(hexStr);
CFRelease(hexStr);
}

View file

@ -1,38 +0,0 @@
/*
* OpenVPN -- An application to securely tunnel IP networks
* over a single UDP port, with support for SSL/TLS-based
* session authentication and key exchange,
* packet encryption, packet authentication, and
* packet compression.
*
* Copyright (C) 2010 Brian Raderman <brian@irregularexpression.org>
* Copyright (C) 2013-2015 Vasily Kulikov <segoon@openwall.com>
*
* This program is free software; you can redistribute it and/or modify
* it under the terms of the GNU General Public License version 2
* as published by the Free Software Foundation.
*
* This program is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
* GNU General Public License for more details.
*
* You should have received a copy of the GNU General Public License along
* with this program; if not, write to the Free Software Foundation, Inc.,
* 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA.
*/
#ifndef __common_osx_h__
#define __common_osx_h__
#include <CoreFoundation/CoreFoundation.h>
void printCFString(CFStringRef str);
char *cfstringToCstr(CFStringRef str);
CFStringRef createHexString(unsigned char *pData, int length);
void printHex(unsigned char *pData, int length);
#endif /*__Common_osx_h__ */

View file

@ -1,79 +0,0 @@
/*
* OpenVPN -- An application to securely tunnel IP networks
* over a single UDP port, with support for SSL/TLS-based
* session authentication and key exchange,
* packet encryption, packet authentication, and
* packet compression.
*
* Copyright (C) 2010 Brian Raderman <brian@irregularexpression.org>
* Copyright (C) 2013-2015 Vasily Kulikov <segoon@openwall.com>
*
* This program is free software; you can redistribute it and/or modify
* it under the terms of the GNU General Public License version 2
* as published by the Free Software Foundation.
*
* This program is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
* GNU General Public License for more details.
*
* You should have received a copy of the GNU General Public License along
* with this program; if not, write to the Free Software Foundation, Inc.,
* 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA.
*/
#include <CommonCrypto/CommonDigest.h>
#include <Security/SecKey.h>
#include <Security/Security.h>
#include "crypto_osx.h"
#include <err.h>
void
printErrorMsg(const char *func, CFErrorRef error)
{
CFStringRef desc = CFErrorCopyDescription(error);
warnx("%s failed: %s", func, CFStringGetCStringPtr(desc, kCFStringEncodingUTF8));
CFRelease(desc);
}
void
printErrorStatusMsg(const char *func, OSStatus status)
{
CFStringRef error;
error = SecCopyErrorMessageString(status, NULL);
if (error)
{
warnx("%s failed: %s", func, CFStringGetCStringPtr(error, kCFStringEncodingUTF8));
CFRelease(error);
}
else
{
warnx("%s failed: %X", func, (int)status);
}
}
void
signData(SecIdentityRef identity, const uint8_t *from, int flen, uint8_t *to, size_t *tlen)
{
SecKeyRef privateKey = NULL;
OSStatus status;
status = SecIdentityCopyPrivateKey(identity, &privateKey);
if (status != noErr)
{
printErrorStatusMsg("signData: SecIdentityCopyPrivateKey", status);
*tlen = 0;
return;
}
status = SecKeyRawSign(privateKey, kSecPaddingPKCS1, from, flen, to, tlen);
CFRelease(privateKey);
if (status != noErr)
{
printErrorStatusMsg("signData: SecKeyRawSign", status);
*tlen = 0;
return;
}
}

View file

@ -1,44 +0,0 @@
/*
* OpenVPN -- An application to securely tunnel IP networks
* over a single UDP port, with support for SSL/TLS-based
* session authentication and key exchange,
* packet encryption, packet authentication, and
* packet compression.
*
* Copyright (C) 2010 Brian Raderman <brian@irregularexpression.org>
* Copyright (C) 2013-2015 Vasily Kulikov <segoon@openwall.com>
*
* This program is free software; you can redistribute it and/or modify
* it under the terms of the GNU General Public License version 2
* as published by the Free Software Foundation.
*
* This program is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
* GNU General Public License for more details.
*
* You should have received a copy of the GNU General Public License along
* with this program; if not, write to the Free Software Foundation, Inc.,
* 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA.
*/
#ifndef __crypto_osx_h__
#define __crypto_osx_h__
#include <CoreFoundation/CoreFoundation.h>
#include <Security/Security.h>
extern OSStatus SecKeyRawSign(
SecKeyRef key,
SecPadding padding,
const uint8_t *dataToSign,
size_t dataToSignLen,
uint8_t *sig,
size_t *sigLen
);
void signData(SecIdentityRef identity, const uint8_t *from, int flen, uint8_t *to, size_t *tlen);
void printErrorMsg(const char *func, CFErrorRef error);
#endif /*__crypto_osx_h__ */

View file

@ -1,161 +0,0 @@
.TH keychain-mcd 8
.SH NAME
keychain-mcd \- Mac OS X Keychain management daemon for OpenVPN
.SH SYNOPSIS
.B keychain-mcd
.I identity-template management-server-ip management-server-port
[
.I password-file
]
.SH DESCRIPTION
.B keychain-mcd
is Mac OS X Keychain management daemon for OpenVPN.
It loads the certificate and private key from the Mac OSX Keychain (Mac OSX Only).
.B keychain-mcd
connects to OpenVPN via management interface and handles
certificate and private key commands (namely
.B NEED-CERTIFICATE
and
.B RSA-SIGN
commands).
.B keychain-mcd
makes it possible to use any smart card supported by Mac OSX using the tokend interface, but also any
kind of certificate, residing in the Keychain, where you have access to
the private key. This option has been tested on the client side with an Aladdin eToken
on Mac OSX Leopard and with software certificates stored in the Keychain on Mac OS X.
Note that Mac OS X might need to present the user with an authentication GUI when the Keychain
is accessed by keychain-mcd.
Use
.B keychain-mcd
along with
.B --management-external-key
and/or
.B --management-external-cert
passed to
.B openvpn.
.SH OPTIONS
.TP
.BR identity-template
A select string which is used to choose a keychain identity from
Mac OS X Keychain or
.I auto
if the identity template is passed from openvpn.
\fBSubject\fR, \fBIssuer\fR, \fBSerial\fR, \fBSHA1\fR, \fBMD5\fR selectors can be used.
To select a certificate based on a string search in the
certificate's subject and/or issuer:
.nf
"SUBJECT:c=US/o=Apple Inc./ou=me.com/cn=username ISSUER:c=US/o=Apple Computer, Inc./ou=Apple Computer Certificate Authority/cn=Apple .Mac Certificate Authority"
.fi
.I "Distinguished Name Component Abbreviations:"
.br
o = organization
.br
ou = organizational unit
.br
c = country
.br
l = locality
.br
st = state
.br
cn = common name
.br
e = email
.br
All of the distinguished name components are optional, although you do need to specify at least one of them. You can
add spaces around the '/' and '=' characters, e.g. "SUBJECT: c = US / o = Apple Inc.". You do not need to specify
both the subject and the issuer, one or the other will work fine.
The identity searching algorithm will return the
certificate it finds that matches all of the criteria you have specified.
If there are several certificates matching all of the criteria then the youngest certificate is returned
(i.e. with the greater "not before" validity field).
You can also include the MD5 and/or SHA1 thumbprints and/or serial number
along with the subject and issuer.
To select a certificate based on certificate's MD5 or SHA1 thumbprint:
.nf
"SHA1: 30 F7 3A 7A B7 73 2A 98 54 33 4A A7 00 6F 6E AC EC D1 EF 02"
"MD5: D5 F5 11 F1 38 EB 5F 4D CF 23 B6 94 E8 33 D8 B5"
.fi
Again, you can include both the SHA1 and the MD5 thumbprints, but you can also use just one of them.
The thumbprint hex strings can easily be copy-and-pasted from the OSX Keychain Access GUI in the Applications/Utilities folder.
The hex string comparison is not case sensitive.
To select a certificate based on certificate's serial number:
"Serial: 3E 9B 6F 02 00 00 00 01 1F 20"
If
.BR identity-template
equals to
.I auto
then the actual identity template is
obtained from argument of NEED-CERTIFICATE notification of openvpn.
In this case the argument of NEED-CERTIFICATE must begin with 'macosx-keychain:' prefix
and the rest of it must contain the actual identity template in the format described above.
.TP
.BR management-server-ip
OpenVPN management IP to connect to.
Both IPv4 and IPv6 addresses can be used.
.TP
.BR management-server-port
OpenVPN management port to connect to.
Use
.B unix
for
.I management-server-port
and socket path for
.I management-server-ip
to connect to a local unix socket.
.TP
.BR password-file
Password file containing the management password on first line.
The password will be used to connect to
.B openvpn
management interface.
Pass
.I password-file
to
.B keychain-mcd
if
.I pw-file
was specified in
.B --management
option to
.B openvpn.
.SH AUTHOR
Vasily Kulikov <segoon@openwall.com>
.SH "SEE ALSO"
.BR openvpn (8)

View file

@ -1,310 +0,0 @@
/*
* OpenVPN -- An application to securely tunnel IP networks
* over a single UDP port, with support for SSL/TLS-based
* session authentication and key exchange,
* packet encryption, packet authentication, and
* packet compression.
*
* Copyright (C) 2015 Vasily Kulikov <segoon@openwall.com>
*
* This program is free software; you can redistribute it and/or modify
* it under the terms of the GNU General Public License version 2
* as published by the Free Software Foundation.
*
* This program is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
* GNU General Public License for more details.
*
* You should have received a copy of the GNU General Public License along
* with this program; if not, write to the Free Software Foundation, Inc.,
* 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA.
*/
#include <sys/socket.h>
#include <netinet/in.h>
#include <arpa/inet.h>
#include <sys/un.h>
#include <err.h>
#include <netdb.h>
#include <Security/Security.h>
#include <CoreServices/CoreServices.h>
#include "cert_data.h"
#include "crypto_osx.h"
#include "../../src/openvpn/base64.h"
SecIdentityRef
template_to_identity(const char *template)
{
SecIdentityRef identity;
CertDataRef pCertDataTemplate = createCertDataFromString(template);
if (pCertDataTemplate == NULL)
{
errx(1, "Bad certificate template");
}
identity = findIdentity(pCertDataTemplate);
if (identity == NULL)
{
errx(1, "No such identify");
}
fprintf(stderr, "Identity found\n");
destroyCertData(pCertDataTemplate);
return identity;
}
int
connect_to_management_server(const char *ip, const char *port)
{
int fd;
struct sockaddr_un addr_un;
struct sockaddr *addr;
size_t addr_len;
if (strcmp(port, "unix") == 0)
{
addr = (struct sockaddr *)&addr_un;
addr_len = sizeof(addr_un);
addr_un.sun_family = AF_UNIX;
strncpy(addr_un.sun_path, ip, sizeof(addr_un.sun_path));
fd = socket(AF_UNIX, SOCK_STREAM, 0);
}
else
{
int rv;
struct addrinfo *result;
struct addrinfo hints;
memset(&hints, 0, sizeof(hints));
hints.ai_family = AF_UNSPEC;
hints.ai_socktype = SOCK_STREAM;
rv = getaddrinfo(ip, port, &hints, &result);
if (rv < 0)
{
errx(1, "getaddrinfo: %s", gai_strerror(rv));
}
if (result == NULL)
{
errx(1, "getaddrinfo returned 0 addressed");
}
/* Use the first found address */
fd = socket(result->ai_family, result->ai_socktype, result->ai_protocol);
addr = result->ai_addr;
addr_len = result->ai_addrlen;
}
if (fd < 0)
{
err(1, "socket");
}
if (connect(fd, addr, addr_len) < 0)
{
err(1, "connect");
}
return fd;
}
int
is_prefix(const char *s, const char *prefix)
{
return strncmp(s, prefix, strlen(prefix)) == 0;
}
void
handle_rsasign(FILE *man_file, SecIdentityRef identity, const char *input)
{
const char *input_b64 = strchr(input, ':') + 1;
char *input_binary;
int input_len;
char *output_binary;
size_t output_len;
char *output_b64;
input_len = strlen(input_b64)*8/6 + 4;
input_binary = malloc(input_len);
input_len = openvpn_base64_decode(input_b64, input_binary, input_len);
if (input_len < 0)
{
errx(1, "openvpn_base64_decode: overflow");
}
output_len = 1024;
output_binary = malloc(output_len);
signData(identity, (const uint8_t *)input_binary, input_len, (uint8_t *)output_binary, &output_len);
if (output_len == 0)
{
errx(1, "handle_rsasign: failed to sign data");
}
openvpn_base64_encode(output_binary, output_len, &output_b64);
fprintf(man_file, "rsa-sig\n%s\nEND\n", output_b64);
free(output_b64);
free(input_binary);
free(output_binary);
fprintf(stderr, "Handled RSA_SIGN command\n");
}
void
handle_needcertificate(FILE *man_file, SecIdentityRef identity)
{
OSStatus status;
SecCertificateRef certificate = NULL;
CFDataRef data;
const unsigned char *cert;
size_t cert_len;
char *result_b64, *tmp_b64;
status = SecIdentityCopyCertificate(identity, &certificate);
if (status != noErr)
{
const char *msg = GetMacOSStatusErrorString(status);
err(1, "SecIdentityCopyCertificate() failed: %s", msg);
}
data = SecCertificateCopyData(certificate);
if (data == NULL)
{
err(1, "SecCertificateCopyData() returned NULL");
}
cert = CFDataGetBytePtr(data);
cert_len = CFDataGetLength(data);
openvpn_base64_encode(cert, cert_len, &result_b64);
#if 0
fprintf(stderr, "certificate %s\n", result_b64);
#endif
fprintf(man_file, "certificate\n");
fprintf(man_file, "-----BEGIN CERTIFICATE-----\n");
tmp_b64 = result_b64;
while (strlen(tmp_b64) > 64) {
fprintf(man_file, "%.64s\n", tmp_b64);
tmp_b64 += 64;
}
if (*tmp_b64)
{
fprintf(man_file, "%s\n", tmp_b64);
}
fprintf(man_file, "-----END CERTIFICATE-----\n");
fprintf(man_file, "END\n");
free(result_b64);
CFRelease(data);
CFRelease(certificate);
fprintf(stderr, "Handled NEED 'cert' command\n");
}
void
management_loop(SecIdentityRef identity, int man_fd, const char *password)
{
char *buffer = NULL;
size_t buffer_len = 0;
FILE *man = fdopen(man_fd, "w+");
if (man == 0)
{
err(1, "fdopen");
}
if (password)
{
fprintf(man, "%s\n", password);
}
while (1) {
if (getline(&buffer, &buffer_len, man) < 0)
{
err(1, "getline");
}
#if 0
fprintf(stderr, "M: %s", buffer);
#endif
if (is_prefix(buffer, ">RSA_SIGN:"))
{
handle_rsasign(man, identity, buffer);
}
if (is_prefix(buffer, ">NEED-CERTIFICATE"))
{
if (!identity)
{
const char prefix[] = ">NEED-CERTIFICATE:macosx-keychain:";
if (!is_prefix(buffer, prefix))
{
errx(1, "No identity template is passed via command line and " \
"NEED-CERTIFICATE management interface command " \
"misses 'macosx-keychain' prefix.");
}
identity = template_to_identity(buffer+strlen(prefix));
}
handle_needcertificate(man, identity);
}
if (is_prefix(buffer, ">FATAL"))
{
fprintf(stderr, "Fatal message from OpenVPN: %s\n", buffer+7);
}
if (is_prefix(buffer, ">INFO"))
{
fprintf(stderr, "INFO message from OpenVPN: %s\n", buffer+6);
}
}
}
char *
read_password(const char *fname)
{
char *password = NULL;
FILE *pwf = fopen(fname, "r");
size_t n = 0;
if (pwf == NULL)
{
errx(1, "fopen(%s) failed", fname);
}
if (getline(&password, &n, pwf) < 0)
{
err(1, "getline");
}
fclose(pwf);
return password;
}
int
main(int argc, char *argv[])
{
if (argc < 4)
{
err(1, "usage: %s <identity_template> <management_ip> <management_port> [<pw-file>]", argv[0]);
}
char *identity_template = argv[1];
char *s_ip = argv[2];
char *s_port = argv[3];
char *password = NULL;
int man_fd;
if (argc > 4)
{
char *s_pw_file = argv[4];
password = read_password(s_pw_file);
}
SecIdentityRef identity = NULL;
if (strcmp(identity_template, "auto"))
{
identity = template_to_identity(identity_template);
}
man_fd = connect_to_management_server(s_ip, s_port);
fprintf(stderr, "Successfully connected to openvpn\n");
management_loop(identity, man_fd, password);
}

View file

@ -36,6 +36,7 @@
#include "syshead.h"
#include "argv.h"
#include "integer.h"
#include "options.h"
static void

View file

@ -180,7 +180,7 @@ buf_assign(struct buffer *dest, const struct buffer *src)
}
struct buffer
clear_buf()
clear_buf(void)
{
struct buffer buf;
CLEAR(buf);

View file

@ -44,7 +44,7 @@ struct _query_user query_user[QUERY_USER_NUMSLOTS]; /* GLOBAL */
void
query_user_clear()
query_user_clear(void)
{
int i;

View file

@ -46,7 +46,7 @@ extern struct _query_user query_user[]; /**< Global variable, declared in conso
* Wipes all data put into all of the query_user structs
*
*/
void query_user_clear();
void query_user_clear(void);
/**
@ -72,7 +72,7 @@ void query_user_add(char *prompt, size_t prompt_len,
*
* @return True if executing all the defined steps completed successfully
*/
bool query_user_exec_builtin();
bool query_user_exec_builtin(void);
#if defined(ENABLE_SYSTEMD)
@ -83,7 +83,7 @@ bool query_user_exec_builtin();
*
* @return True if executing all the defined steps completed successfully
*/
bool query_user_exec();
bool query_user_exec(void);
#else /* ENABLE_SYSTEMD not defined*/
/**
@ -92,7 +92,7 @@ bool query_user_exec();
*
*/
static bool
query_user_exec()
query_user_exec(void)
{
return query_user_exec_builtin();
}

View file

@ -267,7 +267,7 @@ get_console_input(const char *prompt, const bool echo, char *input, const int ca
*
*/
bool
query_user_exec_builtin()
query_user_exec_builtin(void)
{
bool ret = true; /* Presume everything goes okay */
int i;

View file

@ -42,7 +42,7 @@
*/
static bool
check_systemd_running()
check_systemd_running(void)
{
struct stat c;
@ -96,7 +96,7 @@ get_console_input_systemd(const char *prompt, const bool echo, char *input, cons
*
*/
bool
query_user_exec()
query_user_exec(void)
{
bool ret = true; /* Presume everything goes okay */
int i;

View file

@ -820,7 +820,7 @@ init_key_type(struct key_type *kt, const char *ciphername,
/* given a key and key_type, build a key_ctx */
void
init_key_ctx(struct key_ctx *ctx, struct key *key,
init_key_ctx(struct key_ctx *ctx, const struct key *key,
const struct key_type *kt, int enc,
const char *prefix)
{
@ -1261,7 +1261,7 @@ read_key_file(struct key2 *key2, const char *file, const unsigned int flags)
fd = platform_open(file, O_RDONLY, 0);
if (fd == -1)
{
msg(M_ERR, "Cannot open file key file '%s'", file);
msg(M_ERR, "Cannot open key file '%s'", file);
}
size = platform_read(fd, in.data, in.capacity);
if (size < 0)
@ -1693,7 +1693,7 @@ static int nonce_secret_len = 0; /* GLOBAL */
/* Reset the nonce value, also done periodically to refresh entropy */
static void
prng_reset_nonce()
prng_reset_nonce(void)
{
const int size = md_kt_size(nonce_md) + nonce_secret_len;
#if 1 /* Must be 1 for real usage */
@ -1772,7 +1772,7 @@ prng_bytes(uint8_t *output, int len)
/* an analogue to the random() function, but use prng_bytes */
long int
get_random()
get_random(void)
{
long int l;
prng_bytes((unsigned char *)&l, sizeof(l));

View file

@ -312,7 +312,7 @@ void init_key_type(struct key_type *kt, const char *ciphername,
* Key context functions
*/
void init_key_ctx(struct key_ctx *ctx, struct key *key,
void init_key_ctx(struct key_ctx *ctx, const struct key *key,
const struct key_type *kt, int enc,
const char *prefix);
@ -453,7 +453,7 @@ void prng_init(const char *md_name, const int nonce_secret_len_parm);
*/
void prng_bytes(uint8_t *output, int len);
void prng_uninit();
void prng_uninit(void);
void test_crypto(struct crypto_options *co, struct frame *f);

View file

@ -323,7 +323,7 @@ void cipher_ctx_free(cipher_ctx_t *ctx);
* @param enc Whether to encrypt or decrypt (either
* \c MBEDTLS_OP_ENCRYPT or \c MBEDTLS_OP_DECRYPT).
*/
void cipher_ctx_init(cipher_ctx_t *ctx, uint8_t *key, int key_len,
void cipher_ctx_init(cipher_ctx_t *ctx, const uint8_t *key, int key_len,
const cipher_kt_t *kt, int enc);
/**
@ -391,7 +391,7 @@ const cipher_kt_t *cipher_ctx_get_cipher_kt(const cipher_ctx_t *ctx);
*
* @return \c 0 on failure, \c 1 on success.
*/
int cipher_ctx_reset(cipher_ctx_t *ctx, uint8_t *iv_buf);
int cipher_ctx_reset(cipher_ctx_t *ctx, const uint8_t *iv_buf);
/**
* Updates the given cipher context, providing additional data (AD) for

View file

@ -159,7 +159,7 @@ print_cipher(const cipher_kt_t *info)
}
void
show_available_ciphers()
show_available_ciphers(void)
{
const int *ciphers = mbedtls_cipher_list();
@ -196,7 +196,7 @@ show_available_ciphers()
}
void
show_available_digests()
show_available_digests(void)
{
const int *digests = mbedtls_md_list();
@ -223,7 +223,7 @@ show_available_digests()
}
void
show_available_engines()
show_available_engines(void)
{
printf("Sorry, mbed TLS hardware crypto engine functionality is not "
"available\n");
@ -243,7 +243,7 @@ show_available_engines()
* entropy gathering function.
*/
mbedtls_ctr_drbg_context *
rand_ctx_get()
rand_ctx_get(void)
{
static mbedtls_entropy_context ec = {0};
static mbedtls_ctr_drbg_context cd_ctx = {0};
@ -280,7 +280,7 @@ rand_ctx_get()
#ifdef ENABLE_PREDICTION_RESISTANCE
void
rand_ctx_enable_prediction_resistance()
rand_ctx_enable_prediction_resistance(void)
{
mbedtls_ctr_drbg_context *cd_ctx = rand_ctx_get();
@ -523,7 +523,7 @@ cipher_ctx_free(mbedtls_cipher_context_t *ctx)
}
void
cipher_ctx_init(mbedtls_cipher_context_t *ctx, uint8_t *key, int key_len,
cipher_ctx_init(mbedtls_cipher_context_t *ctx, const uint8_t *key, int key_len,
const mbedtls_cipher_info_t *kt, const mbedtls_operation_t operation)
{
ASSERT(NULL != kt && NULL != ctx);
@ -597,7 +597,7 @@ cipher_ctx_get_cipher_kt(const cipher_ctx_t *ctx)
}
int
cipher_ctx_reset(mbedtls_cipher_context_t *ctx, uint8_t *iv_buf)
cipher_ctx_reset(mbedtls_cipher_context_t *ctx, const uint8_t *iv_buf)
{
if (!mbed_ok(mbedtls_cipher_reset(ctx)))
{

View file

@ -85,13 +85,13 @@ typedef mbedtls_md_context_t hmac_ctx_t;
* added. During initialisation, a personalisation string will be added based
* on the time, the PID, and a pointer to the random context.
*/
mbedtls_ctr_drbg_context *rand_ctx_get();
mbedtls_ctr_drbg_context *rand_ctx_get(void);
#ifdef ENABLE_PREDICTION_RESISTANCE
/**
* Enable prediction resistance on the random number generator.
*/
void rand_ctx_enable_prediction_resistance();
void rand_ctx_enable_prediction_resistance(void);
#endif

View file

@ -280,7 +280,7 @@ print_cipher(const EVP_CIPHER *cipher)
}
void
show_available_ciphers()
show_available_ciphers(void)
{
int nid;
size_t i;
@ -339,7 +339,7 @@ show_available_ciphers()
}
void
show_available_digests()
show_available_digests(void)
{
int nid;
@ -364,7 +364,7 @@ show_available_digests()
}
void
show_available_engines()
show_available_engines(void)
{
#if HAVE_OPENSSL_ENGINE /* Only defined for OpenSSL */
ENGINE *e;
@ -665,7 +665,7 @@ cipher_ctx_free(EVP_CIPHER_CTX *ctx)
}
void
cipher_ctx_init(EVP_CIPHER_CTX *ctx, uint8_t *key, int key_len,
cipher_ctx_init(EVP_CIPHER_CTX *ctx, const uint8_t *key, int key_len,
const EVP_CIPHER *kt, int enc)
{
ASSERT(NULL != kt && NULL != ctx);
@ -732,7 +732,7 @@ cipher_ctx_get_cipher_kt(const cipher_ctx_t *ctx)
int
cipher_ctx_reset(EVP_CIPHER_CTX *ctx, uint8_t *iv_buf)
cipher_ctx_reset(EVP_CIPHER_CTX *ctx, const uint8_t *iv_buf)
{
return EVP_CipherInit_ex(ctx, NULL, NULL, NULL, iv_buf, -1);
}

View file

@ -160,7 +160,7 @@ set_machine_readable_output(bool parsable)
}
void
error_reset()
error_reset(void)
{
use_syslog = std_redir = false;
suppress_timestamps = false;
@ -278,7 +278,7 @@ x_msg_va(const unsigned int flags, const char *format, va_list arglist)
if ((flags & M_ERRNO) && e)
{
openvpn_snprintf(m2, ERR_BUF_SIZE, "%s: %s (errno=%d)",
m1, strerror_ts(e, &gc), e);
m1, strerror(e), e);
SWAP;
}
@ -491,7 +491,7 @@ open_syslog(const char *pgmname, bool stdio_to_null)
}
void
close_syslog()
close_syslog(void)
{
#if SYSLOG_CAPABILITY
if (use_syslog)
@ -646,7 +646,7 @@ unsigned int x_cs_verbose_level; /* GLOBAL */
unsigned int x_cs_err_delay_ms; /* GLOBAL */
void
reset_check_status()
reset_check_status(void)
{
x_cs_info_level = 0;
x_cs_verbose_level = 0;
@ -704,20 +704,15 @@ x_check_status(int status,
{
if (extended_msg)
{
msg(x_cs_info_level, "%s %s [%s]: %s (code=%d)",
description,
msg(x_cs_info_level, "%s %s [%s]: %s (code=%d)", description,
sock ? proto2ascii(sock->info.proto, sock->info.af, true) : "",
extended_msg,
strerror_ts(my_errno, &gc),
my_errno);
extended_msg, strerror(my_errno), my_errno);
}
else
{
msg(x_cs_info_level, "%s %s: %s (code=%d)",
description,
msg(x_cs_info_level, "%s %s: %s (code=%d)", description,
sock ? proto2ascii(sock->info.proto, sock->info.af, true) : "",
strerror_ts(my_errno, &gc),
my_errno);
strerror(my_errno), my_errno);
}
if (x_cs_err_delay_ms)

View file

@ -261,7 +261,7 @@ void msg_forked(void);
void open_syslog(const char *pgmname, bool stdio_to_null);
void close_syslog();
void close_syslog(void);
/* log file output */
void redirect_stdout_stderr(const char *file, bool append);

View file

@ -757,7 +757,7 @@ read_incoming_link(struct context *c)
if (event_timeout_defined(&c->c2.explicit_exit_notification_interval))
{
msg(D_STREAM_ERRORS, "Connection reset during exit notification period, ignoring [%d]", status);
openvpn_sleep(1);
management_sleep(1);
}
else
#endif

View file

@ -610,6 +610,7 @@ init_port_share(struct context *c)
#endif /* if PORT_SHARE */
bool
init_static(void)
{
@ -619,8 +620,20 @@ init_static(void)
crypto_init_dmalloc();
#endif
init_random_seed(); /* init random() function, only used as
* source for weak random numbers */
/*
* Initialize random number seed. random() is only used
* when "weak" random numbers are acceptable.
* SSL library routines are always used when cryptographically
* strong random numbers are required.
*/
struct timeval tv;
if (!gettimeofday(&tv, NULL))
{
const unsigned int seed = (unsigned int) tv.tv_sec ^ tv.tv_usec;
srandom(seed);
}
error_reset(); /* initialize error.c */
reset_check_status(); /* initialize status check code in socket.c */
@ -1904,7 +1917,7 @@ do_close_tun(struct context *c, bool force)
}
void
tun_abort()
tun_abort(void)
{
struct context *c = static_context;
if (c)
@ -1969,7 +1982,7 @@ do_up(struct context *c, bool pulled_options, unsigned int option_types_found)
/* if so, close tun, delete routes, then reinitialize tun and add routes */
msg(M_INFO, "NOTE: Pulled options changed on restart, will need to close and reopen TUN/TAP device.");
do_close_tun(c, true);
openvpn_sleep(1);
management_sleep(1);
c->c2.did_open_tun = do_open_tun(c);
update_time();
}
@ -2263,7 +2276,7 @@ socket_restart_pause(struct context *c)
if (sec)
{
msg(D_RESTART, "Restart pause, %d second(s)", sec);
openvpn_sleep(sec);
management_sleep(sec);
}
}

View file

@ -118,6 +118,24 @@ modulo_add(int x, int y, int mod)
return sum;
}
/*
* Return the next largest power of 2
* or u if u is a power of 2.
*/
static inline size_t
adjust_power_of_2(size_t u)
{
size_t ret = 1;
while (ret < u)
{
ret <<= 1;
ASSERT(ret > 0);
}
return ret;
}
static inline int
index_verify(int index, int size, const char *file, int line)
{

View file

@ -155,7 +155,7 @@ event_timeout_clear(struct event_timeout *et)
}
static inline struct event_timeout
event_timeout_clear_ret()
event_timeout_clear_ret(void)
{
struct event_timeout ret;
event_timeout_clear(&ret);

View file

@ -31,6 +31,7 @@
#if P2MP_SERVER
#include "integer.h"
#include "list.h"
#include "misc.h"

View file

@ -68,7 +68,7 @@ static void man_output_standalone(struct management *man, volatile int *signal_r
static void man_reset_client_socket(struct management *man, const bool exiting);
static void
man_help()
man_help(void)
{
msg(M_CLIENT, "Management Interface for %s", title_string);
msg(M_CLIENT, "Commands:");
@ -1878,17 +1878,15 @@ man_connect(struct management *man)
#if UNIX_SOCK_SUPPORT
if (man->settings.flags & MF_UNIX_SOCK)
{
msg(D_LINK_ERRORS,
"MANAGEMENT: connect to unix socket %s failed: %s",
sockaddr_unix_name(&man->settings.local_unix, "NULL"),
strerror_ts(status, &gc));
msg(D_LINK_ERRORS | M_ERRNO,
"MANAGEMENT: connect to unix socket %s failed",
sockaddr_unix_name(&man->settings.local_unix, "NULL"));
}
else
#endif
msg(D_LINK_ERRORS,
"MANAGEMENT: connect to %s failed: %s",
print_sockaddr(man->settings.local->ai_addr, &gc),
strerror_ts(status, &gc));
msg(D_LINK_ERRORS | M_ERRNO,
"MANAGEMENT: connect to %s failed",
print_sockaddr(man->settings.local->ai_addr, &gc));
throw_signal_soft(SIGTERM, "management-connect-failed");
goto done;
}
@ -2008,9 +2006,8 @@ man_io_error(struct management *man, const char *prefix)
if (!ignore_sys_error(err))
{
struct gc_arena gc = gc_new();
msg(D_MANAGEMENT, "MANAGEMENT: TCP %s error: %s",
prefix,
strerror_ts(err, &gc));
msg(D_MANAGEMENT, "MANAGEMENT: TCP %s error: %s", prefix,
strerror(err));
gc_free(&gc);
return true;
}
@ -3504,7 +3501,9 @@ management_query_user_pass(struct management *man,
*/
if (ret)
{
man->connection.up_query.nocache = up->nocache; /* preserve caller's nocache setting */
/* preserve caller's settings */
man->connection.up_query.nocache = up->nocache;
man->connection.up_query.wait_for_push = up->wait_for_push;
*up = man->connection.up_query;
}
secure_memzero(&man->connection.up_query, sizeof(man->connection.up_query));
@ -4000,9 +3999,25 @@ log_history_ref(const struct log_history *h, const int index)
}
}
#else /* ifdef ENABLE_MANAGEMENT */
static void
dummy(void)
void
management_sleep(const int n)
{
if (management)
{
management_event_loop_n_seconds(management, n);
}
else
{
sleep(n);
}
}
#else /* ifdef ENABLE_MANAGEMENT */
void
management_sleep(const int n)
{
sleep(n);
}
#endif /* ENABLE_MANAGEMENT */

View file

@ -605,4 +605,11 @@ management_bytes_server(struct management *man,
#endif /* MANAGEMENT_DEF_AUTH */
#endif /* ifdef ENABLE_MANAGEMENT */
/**
* A sleep function that services the management layer for n seconds rather
* than doing nothing.
*/
void management_sleep(const int n);
#endif /* ifndef MANAGE_H */

View file

@ -33,6 +33,7 @@
#include "buffer.h"
#include "error.h"
#include "integer.h"
#include "misc.h"
#include "mbuf.h"

View file

@ -145,28 +145,6 @@ run_up_down(const char *command,
gc_free(&gc);
}
/* Write our PID to a file */
void
write_pid(const char *filename)
{
if (filename)
{
unsigned int pid = 0;
FILE *fp = platform_fopen(filename, "w");
if (!fp)
{
msg(M_ERR, "Open error on pid file %s", filename);
}
pid = platform_getpid();
fprintf(fp, "%u\n", pid);
if (platform_fclose(fp))
{
msg(M_ERR, "Close error on pid file %s", filename);
}
}
}
/*
* Set standard file descriptors to /dev/null
*/
@ -445,40 +423,6 @@ openvpn_popen(const struct argv *a, const struct env_set *es)
/*
* Initialize random number seed. random() is only used
* when "weak" random numbers are acceptable.
* OpenSSL routines are always used when cryptographically
* strong random numbers are required.
*/
void
init_random_seed(void)
{
struct timeval tv;
if (!gettimeofday(&tv, NULL))
{
const unsigned int seed = (unsigned int) tv.tv_sec ^ tv.tv_usec;
srandom(seed);
}
}
/* thread-safe strerror */
const char *
strerror_ts(int errnum, struct gc_arena *gc)
{
#ifdef HAVE_STRERROR
struct buffer out = alloc_buf_gc(256, gc);
buf_printf(&out, "%s", openvpn_strerror(errnum, gc));
return BSTR(&out);
#else
return "[error string unavailable]";
#endif
}
/*
* Set environmental variable (int or string).
*
@ -504,29 +448,6 @@ construct_name_value(const char *name, const char *value, struct gc_arena *gc)
return BSTR(&out);
}
bool
deconstruct_name_value(const char *str, const char **name, const char **value, struct gc_arena *gc)
{
char *cp;
ASSERT(str);
ASSERT(name && value);
*name = cp = string_alloc(str, gc);
*value = NULL;
while ((*cp))
{
if (*cp == '=' && !*value)
{
*cp = 0;
*value = cp + 1;
}
++cp;
}
return *name && *value;
}
static bool
env_string_equal(const char *s1, const char *s2)
{
@ -948,10 +869,8 @@ create_temp_file(const char *directory, const char *prefix, struct gc_arena *gc)
else if (fd == -1 && errno != EEXIST)
{
/* Something else went wrong, no need to retry. */
struct gc_arena gcerr = gc_new();
msg(M_FATAL, "Could not create temporary file '%s': %s",
retfname, strerror_ts(errno, &gcerr));
gc_free(&gcerr);
msg(M_FATAL | M_ERRNO, "Could not create temporary file '%s'",
retfname);
return NULL;
}
}
@ -1652,37 +1571,6 @@ make_extended_arg_array(char **p, struct gc_arena *gc)
}
}
void
openvpn_sleep(const int n)
{
#ifdef ENABLE_MANAGEMENT
if (management)
{
management_event_loop_n_seconds(management, n);
return;
}
#endif
sleep(n);
}
/*
* Return the next largest power of 2
* or u if u is a power of 2.
*/
size_t
adjust_power_of_2(size_t u)
{
size_t ret = 1;
while (ret < u)
{
ret <<= 1;
ASSERT(ret > 0);
}
return ret;
}
/*
* Remove security-sensitive strings from control message
* so that they will not be output to log file.

View file

@ -68,8 +68,6 @@ void run_up_down(const char *command,
const char *script_type,
struct env_set *es);
void write_pid(const char *filename);
/* system flags */
#define S_SCRIPT (1<<0)
#define S_FATAL (1<<1)
@ -95,12 +93,6 @@ openvpn_run_script(const struct argv *a, const struct env_set *es, const unsigne
}
#ifdef HAVE_STRERROR
/* a thread-safe version of strerror */
const char *strerror_ts(int errnum, struct gc_arena *gc);
#endif
/* Set standard file descriptors to /dev/null */
void set_std_files_to_null(bool stdin_only);
@ -108,9 +100,6 @@ void set_std_files_to_null(bool stdin_only);
extern int inetd_socket_descriptor;
void save_inetd_socket_descriptor(void);
/* init random() function, only used as source for weak random numbers, when !ENABLE_CRYPTO */
void init_random_seed(void);
/* set/delete environmental variable */
void setenv_str_ex(struct env_set *es,
const char *name,
@ -298,12 +287,6 @@ bool env_safe_to_print(const char *str);
/* returns true if environmental variable may be passed to an external program */
bool env_allowed(const char *str);
/*
* A sleep function that services the management layer for n
* seconds rather than doing nothing.
*/
void openvpn_sleep(const int n);
void configure_path(void);
const char *sanitize_control_message(const char *str, struct gc_arena *gc);
@ -327,8 +310,6 @@ extern const char *iproute_path;
#define SSEC_PW_ENV 3 /* allow calling of built-in programs and user-defined scripts that may receive a password as an environmental variable */
extern int script_security; /* GLOBAL */
/* return the next largest power of 2 */
size_t adjust_power_of_2(size_t u);
#define COMPAT_FLAG_QUERY 0 /** compat_flags operator: Query for a flag */
#define COMPAT_FLAG_SET (1<<0) /** compat_flags operator: Set a compat flag */

View file

@ -797,7 +797,7 @@ tunnel_server_tcp(struct context *top)
multi.top.c2.inotify_fd = inotify_init();
if (multi.top.c2.inotify_fd < 0)
{
msg(D_MULTI_ERRORS, "MULTI: inotify_init error: %s", strerror(errno));
msg(D_MULTI_ERRORS | M_ERRNO, "MULTI: inotify_init error");
}
#endif

View file

@ -326,7 +326,7 @@ tunnel_server_udp_single_threaded(struct context *top)
multi.top.c2.inotify_fd = inotify_init();
if (multi.top.c2.inotify_fd < 0)
{
msg(D_MULTI_ERRORS, "MULTI: inotify_init error: %s", strerror(errno));
msg(D_MULTI_ERRORS | M_ERRNO, "MULTI: inotify_init error");
}
#endif

View file

@ -2356,7 +2356,7 @@ multi_process_post(struct multi_context *m, struct multi_instance *mi, const uns
}
else
{
msg(M_NONFATAL, "MULTI: inotify_add_watch error: %s", strerror(errno));
msg(M_NONFATAL | M_ERRNO, "MULTI: inotify_add_watch error");
}
}
#endif

View file

@ -60,45 +60,47 @@ static void
create_des_keys(const unsigned char *hash, unsigned char *key)
{
key[0] = hash[0];
key[1] = ((hash[0]&1)<<7)|(hash[1]>>1);
key[2] = ((hash[1]&3)<<6)|(hash[2]>>2);
key[3] = ((hash[2]&7)<<5)|(hash[3]>>3);
key[4] = ((hash[3]&15)<<4)|(hash[4]>>4);
key[5] = ((hash[4]&31)<<3)|(hash[5]>>5);
key[6] = ((hash[5]&63)<<2)|(hash[6]>>6);
key[7] = ((hash[6]&127)<<1);
key[1] = ((hash[0] & 1) << 7) | (hash[1] >> 1);
key[2] = ((hash[1] & 3) << 6) | (hash[2] >> 2);
key[3] = ((hash[2] & 7) << 5) | (hash[3] >> 3);
key[4] = ((hash[3] & 15) << 4) | (hash[4] >> 4);
key[5] = ((hash[4] & 31) << 3) | (hash[5] >> 5);
key[6] = ((hash[5] & 63) << 2) | (hash[6] >> 6);
key[7] = ((hash[6] & 127) << 1);
key_des_fixup(key, 8, 1);
}
static void
gen_md4_hash(const char *data, int data_len, char *result)
gen_md4_hash(const uint8_t *data, int data_len, uint8_t *result)
{
/* result is 16 byte md4 hash */
const md_kt_t *md4_kt = md_kt_get("MD4");
char md[MD4_DIGEST_LENGTH];
uint8_t md[MD4_DIGEST_LENGTH];
md_full(md4_kt, data, data_len, md);
memcpy(result, md, MD4_DIGEST_LENGTH);
}
static void
gen_hmac_md5(const char *data, int data_len, const char *key, int key_len,char *result)
gen_hmac_md5(const uint8_t *data, int data_len, const uint8_t *key, int key_len,
uint8_t *result)
{
const md_kt_t *md5_kt = md_kt_get("MD5");
hmac_ctx_t *hmac_ctx = hmac_ctx_new();
hmac_ctx_init(hmac_ctx, key, key_len, md5_kt);
hmac_ctx_update(hmac_ctx, (const unsigned char *)data, data_len);
hmac_ctx_final(hmac_ctx, (unsigned char *)result);
hmac_ctx_update(hmac_ctx, data, data_len);
hmac_ctx_final(hmac_ctx, result);
hmac_ctx_cleanup(hmac_ctx);
hmac_ctx_free(hmac_ctx);
}
static void
gen_timestamp(unsigned char *timestamp)
gen_timestamp(uint8_t *timestamp)
{
/* Copies 8 bytes long timestamp into "timestamp" buffer.
* Timestamp is Little-endian, 64-bit signed value representing the number of tenths of a microsecond since January 1, 1601.
* Timestamp is Little-endian, 64-bit signed value representing the
* number of tenths of a microsecond since January 1, 1601.
*/
UINTEGER64 timestamp_ull;
@ -130,7 +132,7 @@ gen_nonce(unsigned char *nonce)
}
void
my_strupr(unsigned char *str)
my_strupr(char *str)
{
/* converts string to uppercase in place */
@ -150,16 +152,17 @@ unicodize(char *dst, const char *src)
{
dst[i++] = *src;
dst[i++] = 0;
}
while (*src++);
} while (*src++);
return i;
}
static void
add_security_buffer(int sb_offset, void *data, int length, unsigned char *msg_buf, int *msg_bufpos)
add_security_buffer(int sb_offset, void *data, int length,
unsigned char *msg_buf, int *msg_bufpos)
{
/* Adds security buffer data to a message and sets security buffer's offset and length */
/* Adds security buffer data to a message and sets security buffer's
* offset and length */
msg_buf[sb_offset] = (unsigned char)length;
msg_buf[sb_offset + 2] = msg_buf[sb_offset];
msg_buf[sb_offset + 4] = (unsigned char)(*msg_bufpos & 0xff);
@ -186,7 +189,8 @@ ntlm_phase_1(const struct http_proxy_info *p, struct gc_arena *gc)
}
const char *
ntlm_phase_3(const struct http_proxy_info *p, const char *phase_2, struct gc_arena *gc)
ntlm_phase_3(const struct http_proxy_info *p, const char *phase_2,
struct gc_arena *gc)
{
/* NTLM handshake
*
@ -195,19 +199,19 @@ ntlm_phase_3(const struct http_proxy_info *p, const char *phase_2, struct gc_are
*/
char pwbuf[sizeof(p->up.password) * 2]; /* for unicode password */
unsigned char buf2[128]; /* decoded reply from proxy */
unsigned char phase3[464];
uint8_t buf2[128]; /* decoded reply from proxy */
uint8_t phase3[464];
char md4_hash[MD4_DIGEST_LENGTH+5];
char challenge[8], ntlm_response[24];
uint8_t md4_hash[MD4_DIGEST_LENGTH + 5];
uint8_t challenge[8], ntlm_response[24];
int i, ret_val;
char ntlmv2_response[144];
uint8_t ntlmv2_response[144];
char userdomain_u[256]; /* for uppercase unicode username and domain */
char userdomain[128]; /* the same as previous but ascii */
char ntlmv2_hash[MD5_DIGEST_LENGTH];
char ntlmv2_hmacmd5[16];
char *ntlmv2_blob = ntlmv2_response + 16; /* inside ntlmv2_response, length: 128 */
uint8_t ntlmv2_hash[MD5_DIGEST_LENGTH];
uint8_t ntlmv2_hmacmd5[16];
uint8_t *ntlmv2_blob = ntlmv2_response + 16; /* inside ntlmv2_response, length: 128 */
int ntlmv2_blob_size = 0;
int phase3_bufpos = 0x40; /* offset to next security buffer data to be added */
size_t len;
@ -246,12 +250,13 @@ ntlm_phase_3(const struct http_proxy_info *p, const char *phase_2, struct gc_are
/* fill 1st 16 bytes with md4 hash, disregard terminating null */
gen_md4_hash(pwbuf, unicodize(pwbuf, p->up.password) - 2, md4_hash);
int unicode_len = unicodize(pwbuf, p->up.password) - 2;
gen_md4_hash((uint8_t *)pwbuf, unicode_len, md4_hash);
/* pad to 21 bytes */
memset(md4_hash + MD4_DIGEST_LENGTH, 0, 5);
ret_val = openvpn_base64_decode( phase_2, (void *)buf2, -1);
ret_val = openvpn_base64_decode(phase_2, buf2, -1);
if (ret_val < 0)
{
return NULL;
@ -271,7 +276,8 @@ ntlm_phase_3(const struct http_proxy_info *p, const char *phase_2, struct gc_are
int tib_len;
/* NTLMv2 hash */
my_strupr((unsigned char *)strcpy(userdomain, username));
strcpy(userdomain, username);
my_strupr(userdomain);
if (strlen(username) + strlen(domain) < sizeof(userdomain))
{
strcat(userdomain, domain);
@ -281,34 +287,40 @@ ntlm_phase_3(const struct http_proxy_info *p, const char *phase_2, struct gc_are
msg(M_INFO, "Warning: Username or domain too long");
}
unicodize(userdomain_u, userdomain);
gen_hmac_md5(userdomain_u, 2 * strlen(userdomain), md4_hash, MD5_DIGEST_LENGTH, ntlmv2_hash);
gen_hmac_md5((uint8_t *)userdomain_u, 2 * strlen(userdomain), md4_hash,
MD5_DIGEST_LENGTH, ntlmv2_hash);
/* NTLMv2 Blob */
memset(ntlmv2_blob, 0, 128); /* Clear blob buffer */
ntlmv2_blob[0x00] = 1; /* Signature */
ntlmv2_blob[0x01] = 1; /* Signature */
ntlmv2_blob[0x04] = 0; /* Reserved */
gen_timestamp((unsigned char *)&ntlmv2_blob[0x08]); /* 64-bit Timestamp */
gen_nonce((unsigned char *)&ntlmv2_blob[0x10]); /* 64-bit Client Nonce */
gen_timestamp(&ntlmv2_blob[0x08]); /* 64-bit Timestamp */
gen_nonce(&ntlmv2_blob[0x10]); /* 64-bit Client Nonce */
ntlmv2_blob[0x18] = 0; /* Unknown, zero should work */
/* Add target information block to the blob */
if (( *((long *)&buf2[0x14]) & 0x00800000) == 0x00800000) /* Check for Target Information block */
/* Check for Target Information block */
if ((*((long *)&buf2[0x14]) & 0x00800000) == 0x00800000)
{
tib_len = buf2[0x28]; /* Get Target Information block size */
if (tib_len > 96)
{
tib_len = 96;
}
{
char *tib_ptr;
int tib_pos = buf2[0x2c];
uint8_t *tib_ptr;
uint8_t tib_pos = buf2[0x2c];
if (tib_pos + tib_len > sizeof(buf2))
{
return NULL;
}
tib_ptr = buf2 + tib_pos; /* Get Target Information block pointer */
memcpy(&ntlmv2_blob[0x1c], tib_ptr, tib_len); /* Copy Target Information block into the blob */
/* Get Target Information block pointer */
tib_ptr = buf2 + tib_pos;
/* Copy Target Information block into the blob */
memcpy(&ntlmv2_blob[0x1c], tib_ptr, tib_len);
}
}
else
@ -316,7 +328,8 @@ ntlm_phase_3(const struct http_proxy_info *p, const char *phase_2, struct gc_are
tib_len = 0;
}
ntlmv2_blob[0x1c + tib_len] = 0; /* Unknown, zero works */
/* Unknown, zero works */
ntlmv2_blob[0x1c + tib_len] = 0;
/* Get blob length */
ntlmv2_blob_size = 0x20 + tib_len;
@ -325,24 +338,28 @@ ntlm_phase_3(const struct http_proxy_info *p, const char *phase_2, struct gc_are
memcpy(&ntlmv2_response[8], challenge, 8);
/* hmac-md5 */
gen_hmac_md5(&ntlmv2_response[8], ntlmv2_blob_size + 8, ntlmv2_hash, MD5_DIGEST_LENGTH, ntlmv2_hmacmd5);
/* Add hmac-md5 result to the blob */
memcpy(ntlmv2_response, ntlmv2_hmacmd5, MD5_DIGEST_LENGTH); /* Note: This overwrites challenge previously written at ntlmv2_response[8..15] */
gen_hmac_md5(&ntlmv2_response[8], ntlmv2_blob_size + 8, ntlmv2_hash,
MD5_DIGEST_LENGTH, ntlmv2_hmacmd5);
/* Add hmac-md5 result to the blob.
* Note: This overwrites challenge previously written at
* ntlmv2_response[8..15] */
memcpy(ntlmv2_response, ntlmv2_hmacmd5, MD5_DIGEST_LENGTH);
}
else /* Generate NTLM response */
else /* Generate NTLM response */
{
unsigned char key1[DES_KEY_LENGTH], key2[DES_KEY_LENGTH], key3[DES_KEY_LENGTH];
unsigned char key1[DES_KEY_LENGTH], key2[DES_KEY_LENGTH];
unsigned char key3[DES_KEY_LENGTH];
create_des_keys((unsigned char *)md4_hash, key1);
create_des_keys(md4_hash, key1);
cipher_des_encrypt_ecb(key1, challenge, ntlm_response);
create_des_keys((unsigned char *)&(md4_hash[DES_KEY_LENGTH-1]), key2);
create_des_keys(&md4_hash[DES_KEY_LENGTH - 1], key2);
cipher_des_encrypt_ecb(key2, challenge, &ntlm_response[DES_KEY_LENGTH]);
create_des_keys((unsigned char *)&(md4_hash[2*(DES_KEY_LENGTH-1)]), key3);
cipher_des_encrypt_ecb(key3, challenge, &ntlm_response[DES_KEY_LENGTH*2]);
create_des_keys(&md4_hash[2 * (DES_KEY_LENGTH - 1)], key3);
cipher_des_encrypt_ecb(key3, challenge,
&ntlm_response[DES_KEY_LENGTH * 2]);
}
@ -353,7 +370,8 @@ ntlm_phase_3(const struct http_proxy_info *p, const char *phase_2, struct gc_are
if (ntlmv2_enabled) /* NTLMv2 response */
{
add_security_buffer(0x14, ntlmv2_response, ntlmv2_blob_size + 16, phase3, &phase3_bufpos);
add_security_buffer(0x14, ntlmv2_response, ntlmv2_blob_size + 16,
phase3, &phase3_bufpos);
}
else /* NTLM response */
{
@ -361,12 +379,13 @@ ntlm_phase_3(const struct http_proxy_info *p, const char *phase_2, struct gc_are
}
/* username in ascii */
add_security_buffer(0x24, username, strlen(username), phase3, &phase3_bufpos);
add_security_buffer(0x24, username, strlen(username), phase3,
&phase3_bufpos);
/* Set domain. If <domain> is empty, default domain will be used (i.e. proxy's domain) */
/* Set domain. If <domain> is empty, default domain will be used
* (i.e. proxy's domain) */
add_security_buffer(0x1c, domain, strlen(domain), phase3, &phase3_bufpos);
/* other security buffers will be empty */
phase3[0x10] = phase3_bufpos; /* lm not used */
phase3[0x30] = phase3_bufpos; /* no workstation name supplied */
@ -376,7 +395,8 @@ ntlm_phase_3(const struct http_proxy_info *p, const char *phase_2, struct gc_are
phase3[0x3c] = 0x02; /* negotiate oem */
phase3[0x3d] = 0x02; /* negotiate ntlm */
return ((const char *)make_base64_string2((unsigned char *)phase3, phase3_bufpos, gc));
return ((const char *)make_base64_string2((unsigned char *)phase3,
phase3_bufpos, gc));
}
#else /* if NTLM */

View file

@ -31,7 +31,7 @@
*/
static inline int
occ_reset_op()
occ_reset_op(void)
{
return -1;
}

View file

@ -88,34 +88,6 @@ EVP_MD_CTX_new(void)
}
#endif
#if !defined(HAVE_EVP_CIPHER_CTX_FREE)
/**
* Free an existing cipher context
*
* @param ctx The cipher context
*/
static inline void
EVP_CIPHER_CTX_free(EVP_CIPHER_CTX *c)
{
free(c);
}
#endif
#if !defined(HAVE_EVP_CIPHER_CTX_NEW)
/**
* Allocate a new cipher context object
*
* @return A zero'ed cipher context object
*/
static inline EVP_CIPHER_CTX *
EVP_CIPHER_CTX_new(void)
{
EVP_CIPHER_CTX *ctx = NULL;
ALLOC_OBJ_CLEAR(ctx, EVP_CIPHER_CTX);
return ctx;
}
#endif
#if !defined(HAVE_HMAC_CTX_RESET)
/**
* Reset a HMAC context
@ -272,6 +244,20 @@ EVP_PKEY_get0_RSA(EVP_PKEY *pkey)
}
#endif
#if !defined(HAVE_EVP_PKEY_GET0_EC_KEY) && !defined(OPENSSL_NO_EC)
/**
* Get the EC_KEY object of a public key
*
* @param pkey Public key object
* @return The underlying EC_KEY object
*/
static inline EC_KEY *
EVP_PKEY_get0_EC_KEY(EVP_PKEY *pkey)
{
return pkey ? pkey->pkey.ec : NULL;
}
#endif
#if !defined(HAVE_EVP_PKEY_ID)
/**
* Get the PKEY type
@ -638,6 +624,24 @@ RSA_meth_set0_app_data(RSA_METHOD *meth, void *app_data)
}
#endif
#if !defined(HAVE_EC_GROUP_ORDER_BITS) && !defined(OPENSSL_NO_EC)
/**
* Gets the number of bits of the order of an EC_GROUP
*
* @param group EC_GROUP object
* @return number of bits of group order.
*/
static inline int
EC_GROUP_order_bits(const EC_GROUP *group)
{
BIGNUM* order = BN_new();
EC_GROUP_get_order(group, order, NULL);
int bits = BN_num_bits(order);
BN_free(order);
return bits;
}
#endif
/* SSLeay symbols have been renamed in OpenSSL 1.1 */
#if !defined(RSA_F_RSA_OSSL_PRIVATE_ENCRYPT)
#define RSA_F_RSA_OSSL_PRIVATE_ENCRYPT RSA_F_RSA_EAY_PRIVATE_ENCRYPT

View file

@ -33,6 +33,7 @@
#include "forward.h"
#include "multi.h"
#include "win32.h"
#include "platform.h"
#include "memdbg.h"
@ -47,6 +48,27 @@ process_signal_p2p(struct context *c)
return process_signal(c);
}
/* Write our PID to a file */
static void
write_pid(const char *filename)
{
if (filename)
{
unsigned int pid = 0;
FILE *fp = platform_fopen(filename, "w");
if (!fp)
{
msg(M_ERR, "Open error on pid file %s", filename);
}
pid = platform_getpid();
fprintf(fp, "%u\n", pid);
if (fclose(fp))
{
msg(M_ERR, "Close error on pid file %s", filename);
}
}
}
/**************************************************************************/

View file

@ -3137,8 +3137,7 @@ check_file_access(const int type, const char *file, const int mode, const char *
/* Scream if an error is found */
if (errcode > 0)
{
msg(M_NOPREFIX|M_OPTERR, "%s fails with '%s': %s",
opt, file, strerror(errno));
msg(M_NOPREFIX | M_OPTERR | M_ERRNO, "%s fails with '%s'", opt, file);
}
/* Return true if an error occured */

View file

@ -644,7 +644,7 @@ packet_id_debug_print(int msglevel,
#ifdef PID_TEST
void
packet_id_interactive_test()
packet_id_interactive_test(void)
{
struct packet_id pid;
struct packet_id_net pin;

View file

@ -299,7 +299,7 @@ packet_id_persist_save_obj(struct packet_id_persist *p, const struct packet_id *
const char *packet_id_net_print(const struct packet_id_net *pin, bool print_timestamp, struct gc_arena *gc);
#ifdef PID_TEST
void packet_id_interactive_test();
void packet_id_interactive_test(void);
#endif

View file

@ -356,7 +356,7 @@ cleanup:
}
void
pkcs11_terminate()
pkcs11_terminate(void)
{
dmsg(
D_PKCS11_DEBUG,
@ -422,13 +422,13 @@ pkcs11_addProvider(
}
int
pkcs11_logout()
pkcs11_logout(void)
{
return pkcs11h_logout() == CKR_OK;
}
int
pkcs11_management_id_count()
pkcs11_management_id_count(void)
{
pkcs11h_certificate_id_list_t id_list = NULL;
pkcs11h_certificate_id_list_t t = NULL;

View file

@ -174,7 +174,7 @@ platform_nice(int niceval)
errno = 0;
if (nice(niceval) < 0 && errno != 0)
{
msg(M_WARN | M_ERRNO, "WARNING: nice %d failed: %s", niceval, strerror(errno));
msg(M_WARN | M_ERRNO, "WARNING: nice %d failed", niceval);
}
else
{
@ -188,7 +188,7 @@ platform_nice(int niceval)
/* Get current PID */
unsigned int
platform_getpid()
platform_getpid(void)
{
FUZZING_BLOCK;

View file

@ -173,7 +173,7 @@ send_control(const socket_descriptor_t fd, int code)
}
static int
cmsg_size()
cmsg_size(void)
{
return CMSG_SPACE(sizeof(socket_descriptor_t));
}
@ -923,7 +923,7 @@ port_share_open(const char *host,
openvpn_close_socket(fd[1]);
exit(0);
return 0; /* NOTREACHED */
return NULL; /* NOTREACHED */
}
error:

View file

@ -3446,7 +3446,14 @@ get_default_gateway_ipv6(struct route_ipv6_gateway_info *rgi6,
if (nh->nlmsg_type == NLMSG_ERROR)
{
struct nlmsgerr *ne = (struct nlmsgerr *)NLMSG_DATA(nh);
msg(M_WARN, "GDG6: NLSMG_ERROR: error %d\n", ne->error);
/* since linux-4.11 -ENETUNREACH is returned when no route can be
* found. Don't print any error message in this case */
if (ne->error != -ENETUNREACH)
{
msg(M_WARN, "GDG6: NLMSG_ERROR: error %s\n",
strerror(-ne->error));
}
break;
}

View file

@ -495,7 +495,7 @@ openvpn_getaddrinfo(unsigned int flags,
goto done;
}
openvpn_sleep(fail_wait_interval);
management_sleep(fail_wait_interval);
}
ASSERT(res);
@ -1192,7 +1192,7 @@ socket_listen_accept(socket_descriptor_t sd,
if (status <= 0)
{
openvpn_sleep(1);
management_sleep(1);
continue;
}
@ -1227,7 +1227,7 @@ socket_listen_accept(socket_descriptor_t sd,
break;
}
}
openvpn_sleep(1);
management_sleep(1);
}
if (!nowait && openvpn_close_socket(sd))
@ -1296,11 +1296,9 @@ socket_bind(socket_descriptor_t sd,
}
if (bind(sd, cur->ai_addr, cur->ai_addrlen))
{
const int errnum = openvpn_errno();
msg(M_FATAL, "%s: Socket bind failed on local address %s: %s",
msg(M_FATAL | M_ERRNO, "%s: Socket bind failed on local address %s",
prefix,
print_sockaddr_ex(local->ai_addr, ":", PS_SHOW_PORT, &gc),
strerror_ts(errnum, &gc));
print_sockaddr_ex(local->ai_addr, ":", PS_SHOW_PORT, &gc));
}
gc_free(&gc);
}
@ -1376,7 +1374,7 @@ openvpn_connect(socket_descriptor_t sd,
#endif
break;
}
openvpn_sleep(1);
management_sleep(1);
continue;
}
@ -1475,10 +1473,8 @@ socket_connect(socket_descriptor_t *sd,
if (status)
{
msg(D_LINK_ERRORS,
"TCP: connect to %s failed: %s",
print_sockaddr(dest, &gc),
strerror_ts(status, &gc));
msg(D_LINK_ERRORS, "TCP: connect to %s failed: %s",
print_sockaddr(dest, &gc), strerror(status));
openvpn_close_socket(*sd);
*sd = SOCKET_UNDEFINED;
@ -3889,12 +3885,11 @@ socket_bind_unix(socket_descriptor_t sd,
if (bind(sd, (struct sockaddr *) local, sizeof(struct sockaddr_un)))
{
const int errnum = openvpn_errno();
msg(M_FATAL, "%s: Socket bind[%d] failed on unix domain socket %s: %s",
msg(M_FATAL | M_ERRNO,
"%s: Socket bind[%d] failed on unix domain socket %s",
prefix,
(int)sd,
sockaddr_unix_name(local, "NULL"),
strerror_ts(errnum, &gc));
sockaddr_unix_name(local, "NULL"));
}
#ifdef HAVE_UMASK

View file

@ -347,7 +347,7 @@ tls_init_control_channel_frame_parameters(const struct frame *data_channel_frame
}
void
init_ssl_lib()
init_ssl_lib(void)
{
tls_init_lib();
@ -355,7 +355,7 @@ init_ssl_lib()
}
void
free_ssl_lib()
free_ssl_lib(void)
{
crypto_uninit_lib();
prng_uninit();
@ -616,6 +616,11 @@ init_ssl(const struct options *options, struct tls_root_ctx *new_ctx)
tls_ctx_client_new(new_ctx);
}
/* Allowable ciphers */
/* Since @SECLEVEL also influces loading of certificates, set the
* cipher restrictions before loading certificates */
tls_ctx_restrict_ciphers(new_ctx, options->cipher_list);
tls_ctx_set_options(new_ctx, options->ssl_flags);
if (options->pkcs12_file)
@ -708,9 +713,6 @@ init_ssl(const struct options *options, struct tls_root_ctx *new_ctx)
tls_ctx_load_ecdh_params(new_ctx, options->ecdh_curve);
}
/* Allowable ciphers */
tls_ctx_restrict_ciphers(new_ctx, options->cipher_list);
#ifdef ENABLE_CRYPTO_MBEDTLS
/* Personalise the random by mixing in the certificate */
tls_ctx_personalise_random(new_ctx);
@ -1958,7 +1960,7 @@ cleanup:
bool
tls_session_update_crypto_params(struct tls_session *session,
const struct options *options, struct frame *frame)
struct options *options, struct frame *frame)
{
if (!session->opt->server
&& 0 != strcmp(options->ciphername, session->opt->config_ciphername)
@ -1967,6 +1969,8 @@ tls_session_update_crypto_params(struct tls_session *session,
msg(D_TLS_ERRORS, "Error: pushed cipher not allowed - %s not in %s or %s",
options->ciphername, session->opt->config_ciphername,
options->ncp_ciphers);
/* undo cipher push, abort connection setup */
options->ciphername = session->opt->config_ciphername;
return false;
}
@ -2186,16 +2190,6 @@ read_string_alloc(struct buffer *buf)
return str;
}
void
read_string_discard(struct buffer *buf)
{
char *data = read_string_alloc(buf);
if (data)
{
free(data);
}
}
/*
* Handle the reading and writing of key data to and from
* the TLS control channel (cleartext).

View file

@ -481,7 +481,7 @@ void tls_update_remote_addr(struct tls_multi *multi,
* @return true if updating succeeded, false otherwise.
*/
bool tls_session_update_crypto_params(struct tls_session *session,
const struct options *options, struct frame *frame);
struct options *options, struct frame *frame);
/**
* "Poor man's NCP": Use peer cipher if it is an allowed (NCP) cipher.

View file

@ -88,17 +88,17 @@ int pem_password_callback(char *buf, int size, int rwflag, void *u);
* Perform any static initialisation necessary by the library.
* Called on OpenVPN initialisation
*/
void tls_init_lib();
void tls_init_lib(void);
/**
* Free any global SSL library-specific data structures.
*/
void tls_free_lib();
void tls_free_lib(void);
/**
* Clear the underlying SSL library's error state.
*/
void tls_clear_error();
void tls_clear_error(void);
/**
* Parse a TLS version specifier

View file

@ -63,17 +63,17 @@
#include <mbedtls/sha256.h>
void
tls_init_lib()
tls_init_lib(void)
{
}
void
tls_free_lib()
tls_free_lib(void)
{
}
void
tls_clear_error()
tls_clear_error(void)
{
}

View file

@ -69,7 +69,7 @@
int mydata_index; /* GLOBAL */
void
tls_init_lib()
tls_init_lib(void)
{
SSL_library_init();
#ifndef ENABLE_SMALL
@ -82,7 +82,7 @@ tls_init_lib()
}
void
tls_free_lib()
tls_free_lib(void)
{
EVP_cleanup();
#ifndef ENABLE_SMALL
@ -91,7 +91,7 @@ tls_free_lib()
}
void
tls_clear_error()
tls_clear_error(void)
{
ERR_clear_error();
}
@ -484,15 +484,7 @@ tls_ctx_load_ecdh_params(struct tls_root_ctx *ctx, const char *curve_name
/* Generate a new ECDH key for each SSL session (for non-ephemeral ECDH) */
SSL_CTX_set_options(ctx->ctx, SSL_OP_SINGLE_ECDH_USE);
#if OPENSSL_VERSION_NUMBER >= 0x10002000L
/* OpenSSL 1.0.2 and newer can automatically handle ECDH parameter loading */
if (NULL == curve_name)
{
SSL_CTX_set_ecdh_auto(ctx->ctx, 1);
return;
}
#endif
/* For older OpenSSL, we'll have to do the parameter loading on our own */
if (curve_name != NULL)
{
/* Use user supplied curve if given */
@ -501,14 +493,17 @@ tls_ctx_load_ecdh_params(struct tls_root_ctx *ctx, const char *curve_name
}
else
{
/* Extract curve from key */
#if OPENSSL_VERSION_NUMBER >= 0x10002000L
/* OpenSSL 1.0.2 and newer can automatically handle ECDH parameter
* loading */
SSL_CTX_set_ecdh_auto(ctx->ctx, 1);
return;
#else
/* For older OpenSSL we have to extract the curve from key on our own */
EC_KEY *eckey = NULL;
const EC_GROUP *ecgrp = NULL;
EVP_PKEY *pkey = NULL;
#if OPENSSL_VERSION_NUMBER >= 0x10002000L && !defined(LIBRESSL_VERSION_NUMBER)
pkey = SSL_CTX_get0_privatekey(ctx->ctx);
#else
/* Little hack to get private key ref from SSL_CTX, yay OpenSSL... */
SSL *ssl = SSL_new(ctx->ctx);
if (!ssl)
@ -517,7 +512,6 @@ tls_ctx_load_ecdh_params(struct tls_root_ctx *ctx, const char *curve_name
}
pkey = SSL_get_privatekey(ssl);
SSL_free(ssl);
#endif
msg(D_TLS_DEBUG, "Extracting ECDH curve from private key");
@ -526,6 +520,7 @@ tls_ctx_load_ecdh_params(struct tls_root_ctx *ctx, const char *curve_name
{
nid = EC_GROUP_get_curve_name(ecgrp);
}
#endif
}
/* Translate NID back to name , just for kicks */
@ -710,7 +705,7 @@ tls_ctx_add_extra_certs(struct tls_root_ctx *ctx, BIO *bio)
for (;; )
{
cert = NULL;
if (!PEM_read_bio_X509(bio, &cert, 0, NULL)) /* takes ownership of cert */
if (!PEM_read_bio_X509(bio, &cert, NULL, NULL)) /* takes ownership of cert */
{
break;
}
@ -808,12 +803,6 @@ tls_ctx_load_cert_file(struct tls_root_ctx *ctx, const char *cert_file,
tls_ctx_load_cert_file_and_copy(ctx, cert_file, cert_file_inline, NULL);
}
void
tls_ctx_free_cert_file(X509 *x509)
{
X509_free(x509);
}
int
tls_ctx_load_priv_file(struct tls_root_ctx *ctx, const char *priv_key_file,
const char *priv_key_file_inline
@ -1077,6 +1066,13 @@ tls_ctx_use_external_private_key(struct tls_root_ctx *ctx,
ASSERT(pkey); /* NULL before SSL_CTX_use_certificate() is called */
pub_rsa = EVP_PKEY_get0_RSA(pkey);
/* Certificate might not be RSA but DSA or EC */
if (!pub_rsa)
{
crypto_msg(M_WARN, "management-external-key requires a RSA certificate");
goto err;
}
/* initialize RSA object */
const BIGNUM *n = NULL;
const BIGNUM *e = NULL;
@ -1327,7 +1323,7 @@ static time_t biofp_last_open; /* GLOBAL */
static const int biofp_reopen_interval = 600; /* GLOBAL */
static void
close_biofp()
close_biofp(void)
{
if (biofp)
{
@ -1337,7 +1333,7 @@ close_biofp()
}
static void
open_biofp()
open_biofp(void)
{
const time_t current = time(NULL);
const pid_t pid = getpid();
@ -1683,18 +1679,36 @@ print_details(struct key_state_ssl *ks_ssl, const char *prefix)
EVP_PKEY *pkey = X509_get_pubkey(cert);
if (pkey != NULL)
{
if (EVP_PKEY_id(pkey) == EVP_PKEY_RSA && EVP_PKEY_get0_RSA(pkey) != NULL)
if ((EVP_PKEY_id(pkey) == EVP_PKEY_RSA) && (EVP_PKEY_get0_RSA(pkey) != NULL))
{
RSA *rsa = EVP_PKEY_get0_RSA(pkey);
openvpn_snprintf(s2, sizeof(s2), ", %d bit RSA",
RSA_bits(rsa));
}
else if (EVP_PKEY_id(pkey) == EVP_PKEY_DSA && EVP_PKEY_get0_DSA(pkey) != NULL)
else if ((EVP_PKEY_id(pkey) == EVP_PKEY_DSA) && (EVP_PKEY_get0_DSA(pkey) != NULL))
{
DSA *dsa = EVP_PKEY_get0_DSA(pkey);
openvpn_snprintf(s2, sizeof(s2), ", %d bit DSA",
DSA_bits(dsa));
}
#ifndef OPENSSL_NO_EC
else if ((EVP_PKEY_id(pkey) == EVP_PKEY_EC) && (EVP_PKEY_get0_EC_KEY(pkey) != NULL))
{
EC_KEY *ec = EVP_PKEY_get0_EC_KEY(pkey);
const EC_GROUP *group = EC_KEY_get0_group(ec);
const char* curve;
int nid = EC_GROUP_get_curve_name(group);
if (nid == 0 || (curve = OBJ_nid2sn(nid)) == NULL)
{
curve = "Error getting curve name";
}
openvpn_snprintf(s2, sizeof(s2), ", %d bit EC, curve: %s",
EC_GROUP_order_bits(group), curve);
}
#endif
EVP_PKEY_free(pkey);
}
X509_free(cert);
@ -1755,7 +1769,7 @@ show_available_tls_ciphers(const char *cipher_list)
* in the OpenSSL library.
*/
void
show_available_curves()
show_available_curves(void)
{
#ifndef OPENSSL_NO_EC
EC_builtin_curve *curves = NULL;

View file

@ -202,8 +202,8 @@ extract_x509_field_ssl(X509_NAME *x509, const char *field_name, char *out,
{
int lastpos = -1;
int tmp = -1;
X509_NAME_ENTRY *x509ne = 0;
ASN1_STRING *asn1 = 0;
X509_NAME_ENTRY *x509ne = NULL;
ASN1_STRING *asn1 = NULL;
unsigned char *buf = NULL;
ASN1_OBJECT *field_name_obj = OBJ_txt2obj(field_name, 0);

View file

@ -179,7 +179,7 @@ status_flush(struct status_output *so)
const off_t off = lseek(so->fd, (off_t)0, SEEK_CUR);
if (ftruncate(so->fd, off) != 0)
{
msg(M_WARN, "Failed to truncate status file: %s", strerror(errno));
msg(M_WARN | M_ERRNO, "Failed to truncate status file");
}
}
#elif defined(HAVE_CHSIZE)

View file

@ -74,6 +74,8 @@
#ifndef TLSCRYPT_H
#define TLSCRYPT_H
#ifdef ENABLE_CRYPTO
#include "buffer.h"
#include "crypto.h"
#include "session_id.h"
@ -140,4 +142,6 @@ bool tls_crypt_unwrap(const struct buffer *src, struct buffer *dst,
/** @} */
#endif /* ENABLE_CRYPTO */
#endif /* TLSCRYPT_H */

View file

@ -1863,7 +1863,7 @@ open_tun(const char *dev, const char *dev_type, const char *dev_node, struct tun
if (oldtunfd >=0 && android_method == ANDROID_OPEN_AFTER_CLOSE)
{
platform_close(oldtunfd);
openvpn_sleep(2);
management_sleep(2);
}
if (oldtunfd >=0 && android_method == ANDROID_KEEP_OLD_TUN)
@ -2564,8 +2564,7 @@ open_tun(const char *dev, const char *dev_type, const char *dev_node, struct tun
if (ioctl(tt->fd, TUNGIFINFO, &info) < 0)
{
msg(M_WARN | M_ERRNO, "Can't get interface info: %s",
strerror(errno));
msg(M_WARN | M_ERRNO, "Can't get interface info");
}
#ifdef IFF_MULTICAST /* openbsd 4.x doesn't have this */
@ -2574,8 +2573,7 @@ open_tun(const char *dev, const char *dev_type, const char *dev_node, struct tun
if (ioctl(tt->fd, TUNSIFINFO, &info) < 0)
{
msg(M_WARN | M_ERRNO, "Can't set interface info: %s",
strerror(errno));
msg(M_WARN | M_ERRNO, "Can't set interface info");
}
}
}
@ -2664,7 +2662,7 @@ open_tun(const char *dev, const char *dev_type, const char *dev_node, struct tun
i = 1;
if (ioctl(tt->fd, TUNSIFHEAD, &i) < 0) /* multi-af mode on */
{
msg(M_WARN | M_ERRNO, "ioctl(TUNSIFHEAD): %s", strerror(errno));
msg(M_WARN | M_ERRNO, "ioctl(TUNSIFHEAD)");
}
}
}
@ -2797,12 +2795,12 @@ open_tun(const char *dev, const char *dev_type, const char *dev_node, struct tun
if (ioctl(tt->fd, TUNSIFMODE, &i) < 0)
{
msg(M_WARN | M_ERRNO, "ioctl(TUNSIFMODE): %s", strerror(errno));
msg(M_WARN | M_ERRNO, "ioctl(TUNSIFMODE)");
}
i = 1;
if (ioctl(tt->fd, TUNSIFHEAD, &i) < 0)
{
msg(M_WARN | M_ERRNO, "ioctl(TUNSIFHEAD): %s", strerror(errno));
msg(M_WARN | M_ERRNO, "ioctl(TUNSIFHEAD)");
}
}
}
@ -3023,16 +3021,14 @@ utun_open_helper(struct ctl_info ctlInfo, int utunnum)
if (fd < 0)
{
msg(M_INFO, "Opening utun (%s): %s", "socket(SYSPROTO_CONTROL)",
strerror(errno));
msg(M_INFO | M_ERRNO, "Opening utun (socket(SYSPROTO_CONTROL))");
return -2;
}
if (ioctl(fd, CTLIOCGINFO, &ctlInfo) == -1)
{
platform_close(fd);
msg(M_INFO, "Opening utun (%s): %s", "ioctl(CTLIOCGINFO)",
strerror(errno));
msg(M_INFO | M_ERRNO, "Opening utun (ioctl(CTLIOCGINFO))");
return -2;
}
@ -3050,8 +3046,7 @@ utun_open_helper(struct ctl_info ctlInfo, int utunnum)
if (connect(fd, (struct sockaddr *)&sc, sizeof(sc)) < 0)
{
msg(M_INFO, "Opening utun (%s): %s", "connect(AF_SYS_CONTROL)",
strerror(errno));
msg(M_INFO | M_ERRNO, "Opening utun (connect(AF_SYS_CONTROL))");
platform_close(fd);
return -1;
}
@ -5005,7 +5000,7 @@ netsh_command(const struct argv *a, int n, int msglevel)
for (i = 0; i < n; ++i)
{
bool status;
openvpn_sleep(1);
management_sleep(1);
netcmd_semaphore_lock();
argv_msg_prefix(M_INFO, a, "NETSH");
status = openvpn_execve_check(a, NULL, 0, "ERROR: netsh command failed");
@ -5014,7 +5009,7 @@ netsh_command(const struct argv *a, int n, int msglevel)
{
return;
}
openvpn_sleep(4);
management_sleep(4);
}
msg(msglevel, "NETSH: command failed");
}
@ -5997,7 +5992,7 @@ open_tun(const char *dev, const char *dev_type, const char *dev_node, struct tun
if (s > 0)
{
msg(M_INFO, "Sleeping for %d seconds...", s);
openvpn_sleep(s);
management_sleep(s);
}
}

View file

@ -1235,7 +1235,7 @@ set_win_sys_path_via_env(struct env_set *es)
const char *
win_get_tempdir()
win_get_tempdir(void)
{
static char tmpdir[MAX_PATH];
WCHAR wtmpdir[MAX_PATH];
@ -1398,7 +1398,7 @@ win_wfp_uninit(const NET_IFINDEX index, const HANDLE msg_channel)
}
int
win32_version_info()
win32_version_info(void)
{
if (!IsWindowsXPOrGreater())
{
@ -1426,7 +1426,7 @@ win32_version_info()
}
bool
win32_is_64bit()
win32_is_64bit(void)
{
#if defined(_WIN64)
return true; /* 64-bit programs run only on Win64 */

View file

@ -285,7 +285,7 @@ char *get_win_sys_path(void);
void fork_to_self(const char *cmdline);
/* Find temporary directory */
const char *win_get_tempdir();
const char *win_get_tempdir(void);
/* Convert a string from UTF-8 to UCS-2 */
WCHAR *wide_string(const char *utf8, struct gc_arena *gc);
@ -299,7 +299,7 @@ bool win_wfp_uninit(const NET_IFINDEX index, const HANDLE msg_channel);
#define WIN_7 2
#define WIN_8 3
int win32_version_info();
int win32_version_info(void);
/*
* String representation of Windows version number and name, see

View file

@ -13,24 +13,6 @@
#include "argv.h"
#include "buffer.h"
/*
* This is defined here to prevent #include'ing misc.h
* which makes things difficult beyond any recognition
*/
size_t
adjust_power_of_2(size_t u)
{
size_t ret = 1;
while (ret < u)
{
ret <<= 1;
assert(ret > 0);
}
return ret;
}
/* Defines for use in the tests and the mock parse_line() */
#define PATH1 "/s p a c e"
#define PATH2 "/foo bar/baz"