diff options
Diffstat (limited to 'roms/edk2/CryptoPkg/Library/OpensslLib/openssl/crypto/bio')
25 files changed, 10929 insertions, 0 deletions
diff --git a/roms/edk2/CryptoPkg/Library/OpensslLib/openssl/crypto/bio/b_addr.c b/roms/edk2/CryptoPkg/Library/OpensslLib/openssl/crypto/bio/b_addr.c new file mode 100644 index 000000000..d11268b6d --- /dev/null +++ b/roms/edk2/CryptoPkg/Library/OpensslLib/openssl/crypto/bio/b_addr.c @@ -0,0 +1,924 @@ +/* + * Copyright 2016-2019 The OpenSSL Project Authors. All Rights Reserved. + * + * Licensed under the OpenSSL license (the "License"). You may not use + * this file except in compliance with the License. You can obtain a copy + * in the file LICENSE in the source distribution or at + * https://www.openssl.org/source/license.html + */ + +#include <assert.h> +#include <string.h> + +#include "bio_local.h" +#include <openssl/crypto.h> + +#ifndef OPENSSL_NO_SOCK +#include <openssl/err.h> +#include <openssl/buffer.h> +#include "internal/thread_once.h" + +CRYPTO_RWLOCK *bio_lookup_lock; +static CRYPTO_ONCE bio_lookup_init = CRYPTO_ONCE_STATIC_INIT; + +/* + * Throughout this file and bio_local.h, the existence of the macro + * AI_PASSIVE is used to detect the availability of struct addrinfo, + * getnameinfo() and getaddrinfo(). If that macro doesn't exist, + * we use our own implementation instead, using gethostbyname, + * getservbyname and a few other. + */ + +/********************************************************************** + * + * Address structure + * + */ + +BIO_ADDR *BIO_ADDR_new(void) +{ + BIO_ADDR *ret = OPENSSL_zalloc(sizeof(*ret)); + + if (ret == NULL) { + BIOerr(BIO_F_BIO_ADDR_NEW, ERR_R_MALLOC_FAILURE); + return NULL; + } + + ret->sa.sa_family = AF_UNSPEC; + return ret; +} + +void BIO_ADDR_free(BIO_ADDR *ap) +{ + OPENSSL_free(ap); +} + +void BIO_ADDR_clear(BIO_ADDR *ap) +{ + memset(ap, 0, sizeof(*ap)); + ap->sa.sa_family = AF_UNSPEC; +} + +/* + * BIO_ADDR_make - non-public routine to fill a BIO_ADDR with the contents + * of a struct sockaddr. + */ +int BIO_ADDR_make(BIO_ADDR *ap, const struct sockaddr *sa) +{ + if (sa->sa_family == AF_INET) { + memcpy(&(ap->s_in), sa, sizeof(struct sockaddr_in)); + return 1; + } +#ifdef AF_INET6 + if (sa->sa_family == AF_INET6) { + memcpy(&(ap->s_in6), sa, sizeof(struct sockaddr_in6)); + return 1; + } +#endif +#ifdef AF_UNIX + if (sa->sa_family == AF_UNIX) { + memcpy(&(ap->s_un), sa, sizeof(struct sockaddr_un)); + return 1; + } +#endif + + return 0; +} + +int BIO_ADDR_rawmake(BIO_ADDR *ap, int family, + const void *where, size_t wherelen, + unsigned short port) +{ +#ifdef AF_UNIX + if (family == AF_UNIX) { + if (wherelen + 1 > sizeof(ap->s_un.sun_path)) + return 0; + memset(&ap->s_un, 0, sizeof(ap->s_un)); + ap->s_un.sun_family = family; + strncpy(ap->s_un.sun_path, where, sizeof(ap->s_un.sun_path) - 1); + return 1; + } +#endif + if (family == AF_INET) { + if (wherelen != sizeof(struct in_addr)) + return 0; + memset(&ap->s_in, 0, sizeof(ap->s_in)); + ap->s_in.sin_family = family; + ap->s_in.sin_port = port; + ap->s_in.sin_addr = *(struct in_addr *)where; + return 1; + } +#ifdef AF_INET6 + if (family == AF_INET6) { + if (wherelen != sizeof(struct in6_addr)) + return 0; + memset(&ap->s_in6, 0, sizeof(ap->s_in6)); + ap->s_in6.sin6_family = family; + ap->s_in6.sin6_port = port; + ap->s_in6.sin6_addr = *(struct in6_addr *)where; + return 1; + } +#endif + + return 0; +} + +int BIO_ADDR_family(const BIO_ADDR *ap) +{ + return ap->sa.sa_family; +} + +int BIO_ADDR_rawaddress(const BIO_ADDR *ap, void *p, size_t *l) +{ + size_t len = 0; + const void *addrptr = NULL; + + if (ap->sa.sa_family == AF_INET) { + len = sizeof(ap->s_in.sin_addr); + addrptr = &ap->s_in.sin_addr; + } +#ifdef AF_INET6 + else if (ap->sa.sa_family == AF_INET6) { + len = sizeof(ap->s_in6.sin6_addr); + addrptr = &ap->s_in6.sin6_addr; + } +#endif +#ifdef AF_UNIX + else if (ap->sa.sa_family == AF_UNIX) { + len = strlen(ap->s_un.sun_path); + addrptr = &ap->s_un.sun_path; + } +#endif + + if (addrptr == NULL) + return 0; + + if (p != NULL) { + memcpy(p, addrptr, len); + } + if (l != NULL) + *l = len; + + return 1; +} + +unsigned short BIO_ADDR_rawport(const BIO_ADDR *ap) +{ + if (ap->sa.sa_family == AF_INET) + return ap->s_in.sin_port; +#ifdef AF_INET6 + if (ap->sa.sa_family == AF_INET6) + return ap->s_in6.sin6_port; +#endif + return 0; +} + +/*- + * addr_strings - helper function to get host and service names + * @ap: the BIO_ADDR that has the input info + * @numeric: 0 if actual names should be returned, 1 if the numeric + * representation should be returned. + * @hostname: a pointer to a pointer to a memory area to store the + * host name or numeric representation. Unused if NULL. + * @service: a pointer to a pointer to a memory area to store the + * service name or numeric representation. Unused if NULL. + * + * The return value is 0 on failure, with the error code in the error + * stack, and 1 on success. + */ +static int addr_strings(const BIO_ADDR *ap, int numeric, + char **hostname, char **service) +{ + if (BIO_sock_init() != 1) + return 0; + + if (1) { +#ifdef AI_PASSIVE + int ret = 0; + char host[NI_MAXHOST] = "", serv[NI_MAXSERV] = ""; + int flags = 0; + + if (numeric) + flags |= NI_NUMERICHOST | NI_NUMERICSERV; + + if ((ret = getnameinfo(BIO_ADDR_sockaddr(ap), + BIO_ADDR_sockaddr_size(ap), + host, sizeof(host), serv, sizeof(serv), + flags)) != 0) { +# ifdef EAI_SYSTEM + if (ret == EAI_SYSTEM) { + SYSerr(SYS_F_GETNAMEINFO, get_last_socket_error()); + BIOerr(BIO_F_ADDR_STRINGS, ERR_R_SYS_LIB); + } else +# endif + { + BIOerr(BIO_F_ADDR_STRINGS, ERR_R_SYS_LIB); + ERR_add_error_data(1, gai_strerror(ret)); + } + return 0; + } + + /* VMS getnameinfo() has a bug, it doesn't fill in serv, which + * leaves it with whatever garbage that happens to be there. + * However, we initialise serv with the empty string (serv[0] + * is therefore NUL), so it gets real easy to detect when things + * didn't go the way one might expect. + */ + if (serv[0] == '\0') { + BIO_snprintf(serv, sizeof(serv), "%d", + ntohs(BIO_ADDR_rawport(ap))); + } + + if (hostname != NULL) + *hostname = OPENSSL_strdup(host); + if (service != NULL) + *service = OPENSSL_strdup(serv); + } else { +#endif + if (hostname != NULL) + *hostname = OPENSSL_strdup(inet_ntoa(ap->s_in.sin_addr)); + if (service != NULL) { + char serv[6]; /* port is 16 bits => max 5 decimal digits */ + BIO_snprintf(serv, sizeof(serv), "%d", ntohs(ap->s_in.sin_port)); + *service = OPENSSL_strdup(serv); + } + } + + if ((hostname != NULL && *hostname == NULL) + || (service != NULL && *service == NULL)) { + if (hostname != NULL) { + OPENSSL_free(*hostname); + *hostname = NULL; + } + if (service != NULL) { + OPENSSL_free(*service); + *service = NULL; + } + BIOerr(BIO_F_ADDR_STRINGS, ERR_R_MALLOC_FAILURE); + return 0; + } + + return 1; +} + +char *BIO_ADDR_hostname_string(const BIO_ADDR *ap, int numeric) +{ + char *hostname = NULL; + + if (addr_strings(ap, numeric, &hostname, NULL)) + return hostname; + + return NULL; +} + +char *BIO_ADDR_service_string(const BIO_ADDR *ap, int numeric) +{ + char *service = NULL; + + if (addr_strings(ap, numeric, NULL, &service)) + return service; + + return NULL; +} + +char *BIO_ADDR_path_string(const BIO_ADDR *ap) +{ +#ifdef AF_UNIX + if (ap->sa.sa_family == AF_UNIX) + return OPENSSL_strdup(ap->s_un.sun_path); +#endif + return NULL; +} + +/* + * BIO_ADDR_sockaddr - non-public routine to return the struct sockaddr + * for a given BIO_ADDR. In reality, this is simply a type safe cast. + * The returned struct sockaddr is const, so it can't be tampered with. + */ +const struct sockaddr *BIO_ADDR_sockaddr(const BIO_ADDR *ap) +{ + return &(ap->sa); +} + +/* + * BIO_ADDR_sockaddr_noconst - non-public function that does the same + * as BIO_ADDR_sockaddr, but returns a non-const. USE WITH CARE, as + * it allows you to tamper with the data (and thereby the contents + * of the input BIO_ADDR). + */ +struct sockaddr *BIO_ADDR_sockaddr_noconst(BIO_ADDR *ap) +{ + return &(ap->sa); +} + +/* + * BIO_ADDR_sockaddr_size - non-public function that returns the size + * of the struct sockaddr the BIO_ADDR is using. If the protocol family + * isn't set or is something other than AF_INET, AF_INET6 or AF_UNIX, + * the size of the BIO_ADDR type is returned. + */ +socklen_t BIO_ADDR_sockaddr_size(const BIO_ADDR *ap) +{ + if (ap->sa.sa_family == AF_INET) + return sizeof(ap->s_in); +#ifdef AF_INET6 + if (ap->sa.sa_family == AF_INET6) + return sizeof(ap->s_in6); +#endif +#ifdef AF_UNIX + if (ap->sa.sa_family == AF_UNIX) + return sizeof(ap->s_un); +#endif + return sizeof(*ap); +} + +/********************************************************************** + * + * Address info database + * + */ + +const BIO_ADDRINFO *BIO_ADDRINFO_next(const BIO_ADDRINFO *bai) +{ + if (bai != NULL) + return bai->bai_next; + return NULL; +} + +int BIO_ADDRINFO_family(const BIO_ADDRINFO *bai) +{ + if (bai != NULL) + return bai->bai_family; + return 0; +} + +int BIO_ADDRINFO_socktype(const BIO_ADDRINFO *bai) +{ + if (bai != NULL) + return bai->bai_socktype; + return 0; +} + +int BIO_ADDRINFO_protocol(const BIO_ADDRINFO *bai) +{ + if (bai != NULL) { + if (bai->bai_protocol != 0) + return bai->bai_protocol; + +#ifdef AF_UNIX + if (bai->bai_family == AF_UNIX) + return 0; +#endif + + switch (bai->bai_socktype) { + case SOCK_STREAM: + return IPPROTO_TCP; + case SOCK_DGRAM: + return IPPROTO_UDP; + default: + break; + } + } + return 0; +} + +/* + * BIO_ADDRINFO_sockaddr_size - non-public function that returns the size + * of the struct sockaddr inside the BIO_ADDRINFO. + */ +socklen_t BIO_ADDRINFO_sockaddr_size(const BIO_ADDRINFO *bai) +{ + if (bai != NULL) + return bai->bai_addrlen; + return 0; +} + +/* + * BIO_ADDRINFO_sockaddr - non-public function that returns bai_addr + * as the struct sockaddr it is. + */ +const struct sockaddr *BIO_ADDRINFO_sockaddr(const BIO_ADDRINFO *bai) +{ + if (bai != NULL) + return bai->bai_addr; + return NULL; +} + +const BIO_ADDR *BIO_ADDRINFO_address(const BIO_ADDRINFO *bai) +{ + if (bai != NULL) + return (BIO_ADDR *)bai->bai_addr; + return NULL; +} + +void BIO_ADDRINFO_free(BIO_ADDRINFO *bai) +{ + if (bai == NULL) + return; + +#ifdef AI_PASSIVE +# ifdef AF_UNIX +# define _cond bai->bai_family != AF_UNIX +# else +# define _cond 1 +# endif + if (_cond) { + freeaddrinfo(bai); + return; + } +#endif + + /* Free manually when we know that addrinfo_wrap() was used. + * See further comment above addrinfo_wrap() + */ + while (bai != NULL) { + BIO_ADDRINFO *next = bai->bai_next; + OPENSSL_free(bai->bai_addr); + OPENSSL_free(bai); + bai = next; + } +} + +/********************************************************************** + * + * Service functions + * + */ + +/*- + * The specs in hostserv can take these forms: + * + * host:service => *host = "host", *service = "service" + * host:* => *host = "host", *service = NULL + * host: => *host = "host", *service = NULL + * :service => *host = NULL, *service = "service" + * *:service => *host = NULL, *service = "service" + * + * in case no : is present in the string, the result depends on + * hostserv_prio, as follows: + * + * when hostserv_prio == BIO_PARSE_PRIO_HOST + * host => *host = "host", *service untouched + * + * when hostserv_prio == BIO_PARSE_PRIO_SERV + * service => *host untouched, *service = "service" + * + */ +int BIO_parse_hostserv(const char *hostserv, char **host, char **service, + enum BIO_hostserv_priorities hostserv_prio) +{ + const char *h = NULL; size_t hl = 0; + const char *p = NULL; size_t pl = 0; + + if (*hostserv == '[') { + if ((p = strchr(hostserv, ']')) == NULL) + goto spec_err; + h = hostserv + 1; + hl = p - h; + p++; + if (*p == '\0') + p = NULL; + else if (*p != ':') + goto spec_err; + else { + p++; + pl = strlen(p); + } + } else { + const char *p2 = strrchr(hostserv, ':'); + p = strchr(hostserv, ':'); + + /*- + * Check for more than one colon. There are three possible + * interpretations: + * 1. IPv6 address with port number, last colon being separator. + * 2. IPv6 address only. + * 3. IPv6 address only if hostserv_prio == BIO_PARSE_PRIO_HOST, + * IPv6 address and port number if hostserv_prio == BIO_PARSE_PRIO_SERV + * Because of this ambiguity, we currently choose to make it an + * error. + */ + if (p != p2) + goto amb_err; + + if (p != NULL) { + h = hostserv; + hl = p - h; + p++; + pl = strlen(p); + } else if (hostserv_prio == BIO_PARSE_PRIO_HOST) { + h = hostserv; + hl = strlen(h); + } else { + p = hostserv; + pl = strlen(p); + } + } + + if (p != NULL && strchr(p, ':')) + goto spec_err; + + if (h != NULL && host != NULL) { + if (hl == 0 + || (hl == 1 && h[0] == '*')) { + *host = NULL; + } else { + *host = OPENSSL_strndup(h, hl); + if (*host == NULL) + goto memerr; + } + } + if (p != NULL && service != NULL) { + if (pl == 0 + || (pl == 1 && p[0] == '*')) { + *service = NULL; + } else { + *service = OPENSSL_strndup(p, pl); + if (*service == NULL) + goto memerr; + } + } + + return 1; + amb_err: + BIOerr(BIO_F_BIO_PARSE_HOSTSERV, BIO_R_AMBIGUOUS_HOST_OR_SERVICE); + return 0; + spec_err: + BIOerr(BIO_F_BIO_PARSE_HOSTSERV, BIO_R_MALFORMED_HOST_OR_SERVICE); + return 0; + memerr: + BIOerr(BIO_F_BIO_PARSE_HOSTSERV, ERR_R_MALLOC_FAILURE); + return 0; +} + +/* addrinfo_wrap is used to build our own addrinfo "chain". + * (it has only one entry, so calling it a chain may be a stretch) + * It should ONLY be called when getaddrinfo() and friends + * aren't available, OR when dealing with a non IP protocol + * family, such as AF_UNIX + * + * the return value is 1 on success, or 0 on failure, which + * only happens if a memory allocation error occurred. + */ +static int addrinfo_wrap(int family, int socktype, + const void *where, size_t wherelen, + unsigned short port, + BIO_ADDRINFO **bai) +{ + if ((*bai = OPENSSL_zalloc(sizeof(**bai))) == NULL) { + BIOerr(BIO_F_ADDRINFO_WRAP, ERR_R_MALLOC_FAILURE); + return 0; + } + + (*bai)->bai_family = family; + (*bai)->bai_socktype = socktype; + if (socktype == SOCK_STREAM) + (*bai)->bai_protocol = IPPROTO_TCP; + if (socktype == SOCK_DGRAM) + (*bai)->bai_protocol = IPPROTO_UDP; +#ifdef AF_UNIX + if (family == AF_UNIX) + (*bai)->bai_protocol = 0; +#endif + { + /* Magic: We know that BIO_ADDR_sockaddr_noconst is really + just an advanced cast of BIO_ADDR* to struct sockaddr * + by the power of union, so while it may seem that we're + creating a memory leak here, we are not. It will be + all right. */ + BIO_ADDR *addr = BIO_ADDR_new(); + if (addr != NULL) { + BIO_ADDR_rawmake(addr, family, where, wherelen, port); + (*bai)->bai_addr = BIO_ADDR_sockaddr_noconst(addr); + } + } + (*bai)->bai_next = NULL; + if ((*bai)->bai_addr == NULL) { + BIO_ADDRINFO_free(*bai); + *bai = NULL; + return 0; + } + return 1; +} + +DEFINE_RUN_ONCE_STATIC(do_bio_lookup_init) +{ + if (!OPENSSL_init_crypto(0, NULL)) + return 0; + bio_lookup_lock = CRYPTO_THREAD_lock_new(); + return bio_lookup_lock != NULL; +} + +int BIO_lookup(const char *host, const char *service, + enum BIO_lookup_type lookup_type, + int family, int socktype, BIO_ADDRINFO **res) +{ + return BIO_lookup_ex(host, service, lookup_type, family, socktype, 0, res); +} + +/*- + * BIO_lookup_ex - look up the node and service you want to connect to. + * @node: the node you want to connect to. + * @service: the service you want to connect to. + * @lookup_type: declare intent with the result, client or server. + * @family: the address family you want to use. Use AF_UNSPEC for any, or + * AF_INET, AF_INET6 or AF_UNIX. + * @socktype: The socket type you want to use. Can be SOCK_STREAM, SOCK_DGRAM + * or 0 for all. + * @protocol: The protocol to use, e.g. IPPROTO_TCP or IPPROTO_UDP or 0 for all. + * Note that some platforms may not return IPPROTO_SCTP without + * explicitly requesting it (i.e. IPPROTO_SCTP may not be returned + * with 0 for the protocol) + * @res: Storage place for the resulting list of returned addresses + * + * This will do a lookup of the node and service that you want to connect to. + * It returns a linked list of different addresses you can try to connect to. + * + * When no longer needed you should call BIO_ADDRINFO_free() to free the result. + * + * The return value is 1 on success or 0 in case of error. + */ +int BIO_lookup_ex(const char *host, const char *service, int lookup_type, + int family, int socktype, int protocol, BIO_ADDRINFO **res) +{ + int ret = 0; /* Assume failure */ + + switch(family) { + case AF_INET: +#ifdef AF_INET6 + case AF_INET6: +#endif +#ifdef AF_UNIX + case AF_UNIX: +#endif +#ifdef AF_UNSPEC + case AF_UNSPEC: +#endif + break; + default: + BIOerr(BIO_F_BIO_LOOKUP_EX, BIO_R_UNSUPPORTED_PROTOCOL_FAMILY); + return 0; + } + +#ifdef AF_UNIX + if (family == AF_UNIX) { + if (addrinfo_wrap(family, socktype, host, strlen(host), 0, res)) + return 1; + else + BIOerr(BIO_F_BIO_LOOKUP_EX, ERR_R_MALLOC_FAILURE); + return 0; + } +#endif + + if (BIO_sock_init() != 1) + return 0; + + if (1) { +#ifdef AI_PASSIVE + int gai_ret = 0, old_ret = 0; + struct addrinfo hints; + + memset(&hints, 0, sizeof(hints)); + + hints.ai_family = family; + hints.ai_socktype = socktype; + hints.ai_protocol = protocol; +# ifdef AI_ADDRCONFIG +# ifdef AF_UNSPEC + if (family == AF_UNSPEC) +# endif + hints.ai_flags |= AI_ADDRCONFIG; +# endif + + if (lookup_type == BIO_LOOKUP_SERVER) + hints.ai_flags |= AI_PASSIVE; + + /* Note that |res| SHOULD be a 'struct addrinfo **' thanks to + * macro magic in bio_local.h + */ +# if defined(AI_ADDRCONFIG) && defined(AI_NUMERICHOST) + retry: +# endif + switch ((gai_ret = getaddrinfo(host, service, &hints, res))) { +# ifdef EAI_SYSTEM + case EAI_SYSTEM: + SYSerr(SYS_F_GETADDRINFO, get_last_socket_error()); + BIOerr(BIO_F_BIO_LOOKUP_EX, ERR_R_SYS_LIB); + break; +# endif +# ifdef EAI_MEMORY + case EAI_MEMORY: + BIOerr(BIO_F_BIO_LOOKUP_EX, ERR_R_MALLOC_FAILURE); + break; +# endif + case 0: + ret = 1; /* Success */ + break; + default: +# if defined(AI_ADDRCONFIG) && defined(AI_NUMERICHOST) + if (hints.ai_flags & AI_ADDRCONFIG) { + hints.ai_flags &= ~AI_ADDRCONFIG; + hints.ai_flags |= AI_NUMERICHOST; + old_ret = gai_ret; + goto retry; + } +# endif + BIOerr(BIO_F_BIO_LOOKUP_EX, ERR_R_SYS_LIB); + ERR_add_error_data(1, gai_strerror(old_ret ? old_ret : gai_ret)); + break; + } + } else { +#endif + const struct hostent *he; +/* + * Because struct hostent is defined for 32-bit pointers only with + * VMS C, we need to make sure that '&he_fallback_address' and + * '&he_fallback_addresses' are 32-bit pointers + */ +#if defined(OPENSSL_SYS_VMS) && defined(__DECC) +# pragma pointer_size save +# pragma pointer_size 32 +#endif + /* Windows doesn't seem to have in_addr_t */ +#ifdef OPENSSL_SYS_WINDOWS + static uint32_t he_fallback_address; + static const char *he_fallback_addresses[] = + { (char *)&he_fallback_address, NULL }; +#else + static in_addr_t he_fallback_address; + static const char *he_fallback_addresses[] = + { (char *)&he_fallback_address, NULL }; +#endif + static const struct hostent he_fallback = + { NULL, NULL, AF_INET, sizeof(he_fallback_address), + (char **)&he_fallback_addresses }; +#if defined(OPENSSL_SYS_VMS) && defined(__DECC) +# pragma pointer_size restore +#endif + + struct servent *se; + /* Apparently, on WIN64, s_proto and s_port have traded places... */ +#ifdef _WIN64 + struct servent se_fallback = { NULL, NULL, NULL, 0 }; +#else + struct servent se_fallback = { NULL, NULL, 0, NULL }; +#endif + + if (!RUN_ONCE(&bio_lookup_init, do_bio_lookup_init)) { + BIOerr(BIO_F_BIO_LOOKUP_EX, ERR_R_MALLOC_FAILURE); + ret = 0; + goto err; + } + + CRYPTO_THREAD_write_lock(bio_lookup_lock); + he_fallback_address = INADDR_ANY; + if (host == NULL) { + he = &he_fallback; + switch(lookup_type) { + case BIO_LOOKUP_CLIENT: + he_fallback_address = INADDR_LOOPBACK; + break; + case BIO_LOOKUP_SERVER: + he_fallback_address = INADDR_ANY; + break; + default: + /* We forgot to handle a lookup type! */ + assert("We forgot to handle a lookup type!" == NULL); + BIOerr(BIO_F_BIO_LOOKUP_EX, ERR_R_INTERNAL_ERROR); + ret = 0; + goto err; + } + } else { + he = gethostbyname(host); + + if (he == NULL) { +#ifndef OPENSSL_SYS_WINDOWS + /* + * This might be misleading, because h_errno is used as if + * it was errno. To minimize mixup add 1000. Underlying + * reason for this is that hstrerror is declared obsolete, + * not to mention that a) h_errno is not always guaranteed + * to be meaningless; b) hstrerror can reside in yet another + * library, linking for sake of hstrerror is an overkill; + * c) this path is not executed on contemporary systems + * anyway [above getaddrinfo/gai_strerror is]. We just let + * system administrator figure this out... + */ +# if defined(OPENSSL_SYS_VXWORKS) + /* h_errno doesn't exist on VxWorks */ + SYSerr(SYS_F_GETHOSTBYNAME, 1000 ); +# else + SYSerr(SYS_F_GETHOSTBYNAME, 1000 + h_errno); +# endif +#else + SYSerr(SYS_F_GETHOSTBYNAME, WSAGetLastError()); +#endif + ret = 0; + goto err; + } + } + + if (service == NULL) { + se_fallback.s_port = 0; + se_fallback.s_proto = NULL; + se = &se_fallback; + } else { + char *endp = NULL; + long portnum = strtol(service, &endp, 10); + +/* + * Because struct servent is defined for 32-bit pointers only with + * VMS C, we need to make sure that 'proto' is a 32-bit pointer. + */ +#if defined(OPENSSL_SYS_VMS) && defined(__DECC) +# pragma pointer_size save +# pragma pointer_size 32 +#endif + char *proto = NULL; +#if defined(OPENSSL_SYS_VMS) && defined(__DECC) +# pragma pointer_size restore +#endif + + switch (socktype) { + case SOCK_STREAM: + proto = "tcp"; + break; + case SOCK_DGRAM: + proto = "udp"; + break; + } + + if (endp != service && *endp == '\0' + && portnum > 0 && portnum < 65536) { + se_fallback.s_port = htons((unsigned short)portnum); + se_fallback.s_proto = proto; + se = &se_fallback; + } else if (endp == service) { + se = getservbyname(service, proto); + + if (se == NULL) { +#ifndef OPENSSL_SYS_WINDOWS + SYSerr(SYS_F_GETSERVBYNAME, errno); +#else + SYSerr(SYS_F_GETSERVBYNAME, WSAGetLastError()); +#endif + goto err; + } + } else { + BIOerr(BIO_F_BIO_LOOKUP_EX, BIO_R_MALFORMED_HOST_OR_SERVICE); + goto err; + } + } + + *res = NULL; + + { +/* + * Because hostent::h_addr_list is an array of 32-bit pointers with VMS C, + * we must make sure our iterator designates the same element type, hence + * the pointer size dance. + */ +#if defined(OPENSSL_SYS_VMS) && defined(__DECC) +# pragma pointer_size save +# pragma pointer_size 32 +#endif + char **addrlistp; +#if defined(OPENSSL_SYS_VMS) && defined(__DECC) +# pragma pointer_size restore +#endif + size_t addresses; + BIO_ADDRINFO *tmp_bai = NULL; + + /* The easiest way to create a linked list from an + array is to start from the back */ + for(addrlistp = he->h_addr_list; *addrlistp != NULL; + addrlistp++) + ; + + for(addresses = addrlistp - he->h_addr_list; + addrlistp--, addresses-- > 0; ) { + if (!addrinfo_wrap(he->h_addrtype, socktype, + *addrlistp, he->h_length, + se->s_port, &tmp_bai)) + goto addrinfo_malloc_err; + tmp_bai->bai_next = *res; + *res = tmp_bai; + continue; + addrinfo_malloc_err: + BIO_ADDRINFO_free(*res); + *res = NULL; + BIOerr(BIO_F_BIO_LOOKUP_EX, ERR_R_MALLOC_FAILURE); + ret = 0; + goto err; + } + + ret = 1; + } + err: + CRYPTO_THREAD_unlock(bio_lookup_lock); + } + + return ret; +} + +#endif /* OPENSSL_NO_SOCK */ diff --git a/roms/edk2/CryptoPkg/Library/OpensslLib/openssl/crypto/bio/b_dump.c b/roms/edk2/CryptoPkg/Library/OpensslLib/openssl/crypto/bio/b_dump.c new file mode 100644 index 000000000..f175e244b --- /dev/null +++ b/roms/edk2/CryptoPkg/Library/OpensslLib/openssl/crypto/bio/b_dump.c @@ -0,0 +1,148 @@ +/* + * Copyright 1995-2018 The OpenSSL Project Authors. All Rights Reserved. + * + * Licensed under the OpenSSL license (the "License"). You may not use + * this file except in compliance with the License. You can obtain a copy + * in the file LICENSE in the source distribution or at + * https://www.openssl.org/source/license.html + */ + +/* + * Stolen from tjh's ssl/ssl_trc.c stuff. + */ + +#include <stdio.h> +#include "bio_local.h" + +#define DUMP_WIDTH 16 +#define DUMP_WIDTH_LESS_INDENT(i) (DUMP_WIDTH - ((i - (i > 6 ? 6 : i) + 3) / 4)) + +#define SPACE(buf, pos, n) (sizeof(buf) - (pos) > (n)) + +int BIO_dump_cb(int (*cb) (const void *data, size_t len, void *u), + void *u, const char *s, int len) +{ + return BIO_dump_indent_cb(cb, u, s, len, 0); +} + +int BIO_dump_indent_cb(int (*cb) (const void *data, size_t len, void *u), + void *u, const char *s, int len, int indent) +{ + int ret = 0; + char buf[288 + 1]; + int i, j, rows, n; + unsigned char ch; + int dump_width; + + if (indent < 0) + indent = 0; + else if (indent > 64) + indent = 64; + + dump_width = DUMP_WIDTH_LESS_INDENT(indent); + rows = len / dump_width; + if ((rows * dump_width) < len) + rows++; + for (i = 0; i < rows; i++) { + n = BIO_snprintf(buf, sizeof(buf), "%*s%04x - ", indent, "", + i * dump_width); + for (j = 0; j < dump_width; j++) { + if (SPACE(buf, n, 3)) { + if (((i * dump_width) + j) >= len) { + strcpy(buf + n, " "); + } else { + ch = ((unsigned char)*(s + i * dump_width + j)) & 0xff; + BIO_snprintf(buf + n, 4, "%02x%c", ch, + j == 7 ? '-' : ' '); + } + n += 3; + } + } + if (SPACE(buf, n, 2)) { + strcpy(buf + n, " "); + n += 2; + } + for (j = 0; j < dump_width; j++) { + if (((i * dump_width) + j) >= len) + break; + if (SPACE(buf, n, 1)) { + ch = ((unsigned char)*(s + i * dump_width + j)) & 0xff; +#ifndef CHARSET_EBCDIC + buf[n++] = ((ch >= ' ') && (ch <= '~')) ? ch : '.'; +#else + buf[n++] = ((ch >= os_toascii[' ']) && (ch <= os_toascii['~'])) + ? os_toebcdic[ch] + : '.'; +#endif + buf[n] = '\0'; + } + } + if (SPACE(buf, n, 1)) { + buf[n++] = '\n'; + buf[n] = '\0'; + } + /* + * if this is the last call then update the ddt_dump thing so that we + * will move the selection point in the debug window + */ + ret += cb((void *)buf, n, u); + } + return ret; +} + +#ifndef OPENSSL_NO_STDIO +static int write_fp(const void *data, size_t len, void *fp) +{ + return UP_fwrite(data, len, 1, fp); +} + +int BIO_dump_fp(FILE *fp, const char *s, int len) +{ + return BIO_dump_cb(write_fp, fp, s, len); +} + +int BIO_dump_indent_fp(FILE *fp, const char *s, int len, int indent) +{ + return BIO_dump_indent_cb(write_fp, fp, s, len, indent); +} +#endif + +static int write_bio(const void *data, size_t len, void *bp) +{ + return BIO_write((BIO *)bp, (const char *)data, len); +} + +int BIO_dump(BIO *bp, const char *s, int len) +{ + return BIO_dump_cb(write_bio, bp, s, len); +} + +int BIO_dump_indent(BIO *bp, const char *s, int len, int indent) +{ + return BIO_dump_indent_cb(write_bio, bp, s, len, indent); +} + +int BIO_hex_string(BIO *out, int indent, int width, unsigned char *data, + int datalen) +{ + int i, j = 0; + + if (datalen < 1) + return 1; + + for (i = 0; i < datalen - 1; i++) { + if (i && !j) + BIO_printf(out, "%*s", indent, ""); + + BIO_printf(out, "%02X:", data[i]); + + j = (j + 1) % width; + if (!j) + BIO_printf(out, "\n"); + } + + if (i && !j) + BIO_printf(out, "%*s", indent, ""); + BIO_printf(out, "%02X", data[datalen - 1]); + return 1; +} diff --git a/roms/edk2/CryptoPkg/Library/OpensslLib/openssl/crypto/bio/b_print.c b/roms/edk2/CryptoPkg/Library/OpensslLib/openssl/crypto/bio/b_print.c new file mode 100644 index 000000000..8ef90ac1d --- /dev/null +++ b/roms/edk2/CryptoPkg/Library/OpensslLib/openssl/crypto/bio/b_print.c @@ -0,0 +1,930 @@ +/* + * Copyright 1995-2018 The OpenSSL Project Authors. All Rights Reserved. + * + * Licensed under the OpenSSL license (the "License"). You may not use + * this file except in compliance with the License. You can obtain a copy + * in the file LICENSE in the source distribution or at + * https://www.openssl.org/source/license.html + */ + +#include <stdio.h> +#include <string.h> +#include "internal/cryptlib.h" +#include "crypto/ctype.h" +#include "internal/numbers.h" +#include <openssl/bio.h> + +/* + * Copyright Patrick Powell 1995 + * This code is based on code written by Patrick Powell <papowell@astart.com> + * It may be used for any purpose as long as this notice remains intact + * on all source code distributions. + */ + +#ifdef HAVE_LONG_DOUBLE +# define LDOUBLE long double +#else +# define LDOUBLE double +#endif + +static int fmtstr(char **, char **, size_t *, size_t *, + const char *, int, int, int); +static int fmtint(char **, char **, size_t *, size_t *, + int64_t, int, int, int, int); +static int fmtfp(char **, char **, size_t *, size_t *, + LDOUBLE, int, int, int, int); +static int doapr_outch(char **, char **, size_t *, size_t *, int); +static int _dopr(char **sbuffer, char **buffer, + size_t *maxlen, size_t *retlen, int *truncated, + const char *format, va_list args); + +/* format read states */ +#define DP_S_DEFAULT 0 +#define DP_S_FLAGS 1 +#define DP_S_MIN 2 +#define DP_S_DOT 3 +#define DP_S_MAX 4 +#define DP_S_MOD 5 +#define DP_S_CONV 6 +#define DP_S_DONE 7 + +/* format flags - Bits */ +/* left-aligned padding */ +#define DP_F_MINUS (1 << 0) +/* print an explicit '+' for a value with positive sign */ +#define DP_F_PLUS (1 << 1) +/* print an explicit ' ' for a value with positive sign */ +#define DP_F_SPACE (1 << 2) +/* print 0/0x prefix for octal/hex and decimal point for floating point */ +#define DP_F_NUM (1 << 3) +/* print leading zeroes */ +#define DP_F_ZERO (1 << 4) +/* print HEX in UPPPERcase */ +#define DP_F_UP (1 << 5) +/* treat value as unsigned */ +#define DP_F_UNSIGNED (1 << 6) + +/* conversion flags */ +#define DP_C_SHORT 1 +#define DP_C_LONG 2 +#define DP_C_LDOUBLE 3 +#define DP_C_LLONG 4 +#define DP_C_SIZE 5 + +/* Floating point formats */ +#define F_FORMAT 0 +#define E_FORMAT 1 +#define G_FORMAT 2 + +/* some handy macros */ +#define char_to_int(p) (p - '0') +#define OSSL_MAX(p,q) ((p >= q) ? p : q) + +static int +_dopr(char **sbuffer, + char **buffer, + size_t *maxlen, + size_t *retlen, int *truncated, const char *format, va_list args) +{ + char ch; + int64_t value; + LDOUBLE fvalue; + char *strvalue; + int min; + int max; + int state; + int flags; + int cflags; + size_t currlen; + + state = DP_S_DEFAULT; + flags = currlen = cflags = min = 0; + max = -1; + ch = *format++; + + while (state != DP_S_DONE) { + if (ch == '\0' || (buffer == NULL && currlen >= *maxlen)) + state = DP_S_DONE; + + switch (state) { + case DP_S_DEFAULT: + if (ch == '%') + state = DP_S_FLAGS; + else + if (!doapr_outch(sbuffer, buffer, &currlen, maxlen, ch)) + return 0; + ch = *format++; + break; + case DP_S_FLAGS: + switch (ch) { + case '-': + flags |= DP_F_MINUS; + ch = *format++; + break; + case '+': + flags |= DP_F_PLUS; + ch = *format++; + break; + case ' ': + flags |= DP_F_SPACE; + ch = *format++; + break; + case '#': + flags |= DP_F_NUM; + ch = *format++; + break; + case '0': + flags |= DP_F_ZERO; + ch = *format++; + break; + default: + state = DP_S_MIN; + break; + } + break; + case DP_S_MIN: + if (ossl_isdigit(ch)) { + min = 10 * min + char_to_int(ch); + ch = *format++; + } else if (ch == '*') { + min = va_arg(args, int); + ch = *format++; + state = DP_S_DOT; + } else + state = DP_S_DOT; + break; + case DP_S_DOT: + if (ch == '.') { + state = DP_S_MAX; + ch = *format++; + } else + state = DP_S_MOD; + break; + case DP_S_MAX: + if (ossl_isdigit(ch)) { + if (max < 0) + max = 0; + max = 10 * max + char_to_int(ch); + ch = *format++; + } else if (ch == '*') { + max = va_arg(args, int); + ch = *format++; + state = DP_S_MOD; + } else + state = DP_S_MOD; + break; + case DP_S_MOD: + switch (ch) { + case 'h': + cflags = DP_C_SHORT; + ch = *format++; + break; + case 'l': + if (*format == 'l') { + cflags = DP_C_LLONG; + format++; + } else + cflags = DP_C_LONG; + ch = *format++; + break; + case 'q': + case 'j': + cflags = DP_C_LLONG; + ch = *format++; + break; + case 'L': + cflags = DP_C_LDOUBLE; + ch = *format++; + break; + case 'z': + cflags = DP_C_SIZE; + ch = *format++; + break; + default: + break; + } + state = DP_S_CONV; + break; + case DP_S_CONV: + switch (ch) { + case 'd': + case 'i': + switch (cflags) { + case DP_C_SHORT: + value = (short int)va_arg(args, int); + break; + case DP_C_LONG: + value = va_arg(args, long int); + break; + case DP_C_LLONG: + value = va_arg(args, int64_t); + break; + case DP_C_SIZE: + value = va_arg(args, ossl_ssize_t); + break; + default: + value = va_arg(args, int); + break; + } + if (!fmtint(sbuffer, buffer, &currlen, maxlen, value, 10, min, + max, flags)) + return 0; + break; + case 'X': + flags |= DP_F_UP; + /* FALLTHROUGH */ + case 'x': + case 'o': + case 'u': + flags |= DP_F_UNSIGNED; + switch (cflags) { + case DP_C_SHORT: + value = (unsigned short int)va_arg(args, unsigned int); + break; + case DP_C_LONG: + value = va_arg(args, unsigned long int); + break; + case DP_C_LLONG: + value = va_arg(args, uint64_t); + break; + case DP_C_SIZE: + value = va_arg(args, size_t); + break; + default: + value = va_arg(args, unsigned int); + break; + } + if (!fmtint(sbuffer, buffer, &currlen, maxlen, value, + ch == 'o' ? 8 : (ch == 'u' ? 10 : 16), + min, max, flags)) + return 0; + break; + case 'f': + if (cflags == DP_C_LDOUBLE) + fvalue = va_arg(args, LDOUBLE); + else + fvalue = va_arg(args, double); + if (!fmtfp(sbuffer, buffer, &currlen, maxlen, fvalue, min, max, + flags, F_FORMAT)) + return 0; + break; + case 'E': + flags |= DP_F_UP; + /* fall thru */ + case 'e': + if (cflags == DP_C_LDOUBLE) + fvalue = va_arg(args, LDOUBLE); + else + fvalue = va_arg(args, double); + if (!fmtfp(sbuffer, buffer, &currlen, maxlen, fvalue, min, max, + flags, E_FORMAT)) + return 0; + break; + case 'G': + flags |= DP_F_UP; + /* fall thru */ + case 'g': + if (cflags == DP_C_LDOUBLE) + fvalue = va_arg(args, LDOUBLE); + else + fvalue = va_arg(args, double); + if (!fmtfp(sbuffer, buffer, &currlen, maxlen, fvalue, min, max, + flags, G_FORMAT)) + return 0; + break; + case 'c': + if (!doapr_outch(sbuffer, buffer, &currlen, maxlen, + va_arg(args, int))) + return 0; + break; + case 's': + strvalue = va_arg(args, char *); + if (max < 0) { + if (buffer) + max = INT_MAX; + else + max = *maxlen; + } + if (!fmtstr(sbuffer, buffer, &currlen, maxlen, strvalue, + flags, min, max)) + return 0; + break; + case 'p': + value = (size_t)va_arg(args, void *); + if (!fmtint(sbuffer, buffer, &currlen, maxlen, + value, 16, min, max, flags | DP_F_NUM)) + return 0; + break; + case 'n': + { + int *num; + num = va_arg(args, int *); + *num = currlen; + } + break; + case '%': + if (!doapr_outch(sbuffer, buffer, &currlen, maxlen, ch)) + return 0; + break; + case 'w': + /* not supported yet, treat as next char */ + ch = *format++; + break; + default: + /* unknown, skip */ + break; + } + ch = *format++; + state = DP_S_DEFAULT; + flags = cflags = min = 0; + max = -1; + break; + case DP_S_DONE: + break; + default: + break; + } + } + /* + * We have to truncate if there is no dynamic buffer and we have filled the + * static buffer. + */ + if (buffer == NULL) { + *truncated = (currlen > *maxlen - 1); + if (*truncated) + currlen = *maxlen - 1; + } + if (!doapr_outch(sbuffer, buffer, &currlen, maxlen, '\0')) + return 0; + *retlen = currlen - 1; + return 1; +} + +static int +fmtstr(char **sbuffer, + char **buffer, + size_t *currlen, + size_t *maxlen, const char *value, int flags, int min, int max) +{ + int padlen; + size_t strln; + int cnt = 0; + + if (value == 0) + value = "<NULL>"; + + strln = OPENSSL_strnlen(value, max < 0 ? SIZE_MAX : (size_t)max); + + padlen = min - strln; + if (min < 0 || padlen < 0) + padlen = 0; + if (max >= 0) { + /* + * Calculate the maximum output including padding. + * Make sure max doesn't overflow into negativity + */ + if (max < INT_MAX - padlen) + max += padlen; + else + max = INT_MAX; + } + if (flags & DP_F_MINUS) + padlen = -padlen; + + while ((padlen > 0) && (max < 0 || cnt < max)) { + if (!doapr_outch(sbuffer, buffer, currlen, maxlen, ' ')) + return 0; + --padlen; + ++cnt; + } + while (strln > 0 && (max < 0 || cnt < max)) { + if (!doapr_outch(sbuffer, buffer, currlen, maxlen, *value++)) + return 0; + --strln; + ++cnt; + } + while ((padlen < 0) && (max < 0 || cnt < max)) { + if (!doapr_outch(sbuffer, buffer, currlen, maxlen, ' ')) + return 0; + ++padlen; + ++cnt; + } + return 1; +} + +static int +fmtint(char **sbuffer, + char **buffer, + size_t *currlen, + size_t *maxlen, int64_t value, int base, int min, int max, int flags) +{ + int signvalue = 0; + const char *prefix = ""; + uint64_t uvalue; + char convert[DECIMAL_SIZE(value) + 3]; + int place = 0; + int spadlen = 0; + int zpadlen = 0; + int caps = 0; + + if (max < 0) + max = 0; + uvalue = value; + if (!(flags & DP_F_UNSIGNED)) { + if (value < 0) { + signvalue = '-'; + uvalue = 0 - (uint64_t)value; + } else if (flags & DP_F_PLUS) + signvalue = '+'; + else if (flags & DP_F_SPACE) + signvalue = ' '; + } + if (flags & DP_F_NUM) { + if (base == 8) + prefix = "0"; + if (base == 16) + prefix = "0x"; + } + if (flags & DP_F_UP) + caps = 1; + do { + convert[place++] = (caps ? "0123456789ABCDEF" : "0123456789abcdef") + [uvalue % (unsigned)base]; + uvalue = (uvalue / (unsigned)base); + } while (uvalue && (place < (int)sizeof(convert))); + if (place == sizeof(convert)) + place--; + convert[place] = 0; + + zpadlen = max - place; + spadlen = + min - OSSL_MAX(max, place) - (signvalue ? 1 : 0) - strlen(prefix); + if (zpadlen < 0) + zpadlen = 0; + if (spadlen < 0) + spadlen = 0; + if (flags & DP_F_ZERO) { + zpadlen = OSSL_MAX(zpadlen, spadlen); + spadlen = 0; + } + if (flags & DP_F_MINUS) + spadlen = -spadlen; + + /* spaces */ + while (spadlen > 0) { + if (!doapr_outch(sbuffer, buffer, currlen, maxlen, ' ')) + return 0; + --spadlen; + } + + /* sign */ + if (signvalue) + if (!doapr_outch(sbuffer, buffer, currlen, maxlen, signvalue)) + return 0; + + /* prefix */ + while (*prefix) { + if (!doapr_outch(sbuffer, buffer, currlen, maxlen, *prefix)) + return 0; + prefix++; + } + + /* zeros */ + if (zpadlen > 0) { + while (zpadlen > 0) { + if (!doapr_outch(sbuffer, buffer, currlen, maxlen, '0')) + return 0; + --zpadlen; + } + } + /* digits */ + while (place > 0) { + if (!doapr_outch(sbuffer, buffer, currlen, maxlen, convert[--place])) + return 0; + } + + /* left justified spaces */ + while (spadlen < 0) { + if (!doapr_outch(sbuffer, buffer, currlen, maxlen, ' ')) + return 0; + ++spadlen; + } + return 1; +} + +static LDOUBLE abs_val(LDOUBLE value) +{ + LDOUBLE result = value; + if (value < 0) + result = -value; + return result; +} + +static LDOUBLE pow_10(int in_exp) +{ + LDOUBLE result = 1; + while (in_exp) { + result *= 10; + in_exp--; + } + return result; +} + +static long roundv(LDOUBLE value) +{ + long intpart; + intpart = (long)value; + value = value - intpart; + if (value >= 0.5) + intpart++; + return intpart; +} + +static int +fmtfp(char **sbuffer, + char **buffer, + size_t *currlen, + size_t *maxlen, LDOUBLE fvalue, int min, int max, int flags, int style) +{ + int signvalue = 0; + LDOUBLE ufvalue; + LDOUBLE tmpvalue; + char iconvert[20]; + char fconvert[20]; + char econvert[20]; + int iplace = 0; + int fplace = 0; + int eplace = 0; + int padlen = 0; + int zpadlen = 0; + long exp = 0; + unsigned long intpart; + unsigned long fracpart; + unsigned long max10; + int realstyle; + + if (max < 0) + max = 6; + + if (fvalue < 0) + signvalue = '-'; + else if (flags & DP_F_PLUS) + signvalue = '+'; + else if (flags & DP_F_SPACE) + signvalue = ' '; + + /* + * G_FORMAT sometimes prints like E_FORMAT and sometimes like F_FORMAT + * depending on the number to be printed. Work out which one it is and use + * that from here on. + */ + if (style == G_FORMAT) { + if (fvalue == 0.0) { + realstyle = F_FORMAT; + } else if (fvalue < 0.0001) { + realstyle = E_FORMAT; + } else if ((max == 0 && fvalue >= 10) + || (max > 0 && fvalue >= pow_10(max))) { + realstyle = E_FORMAT; + } else { + realstyle = F_FORMAT; + } + } else { + realstyle = style; + } + + if (style != F_FORMAT) { + tmpvalue = fvalue; + /* Calculate the exponent */ + if (fvalue != 0.0) { + while (tmpvalue < 1) { + tmpvalue *= 10; + exp--; + } + while (tmpvalue > 10) { + tmpvalue /= 10; + exp++; + } + } + if (style == G_FORMAT) { + /* + * In G_FORMAT the "precision" represents significant digits. We + * always have at least 1 significant digit. + */ + if (max == 0) + max = 1; + /* Now convert significant digits to decimal places */ + if (realstyle == F_FORMAT) { + max -= (exp + 1); + if (max < 0) { + /* + * Should not happen. If we're in F_FORMAT then exp < max? + */ + return 0; + } + } else { + /* + * In E_FORMAT there is always one significant digit in front + * of the decimal point, so: + * significant digits == 1 + decimal places + */ + max--; + } + } + if (realstyle == E_FORMAT) + fvalue = tmpvalue; + } + ufvalue = abs_val(fvalue); + if (ufvalue > ULONG_MAX) { + /* Number too big */ + return 0; + } + intpart = (unsigned long)ufvalue; + + /* + * sorry, we only support 9 digits past the decimal because of our + * conversion method + */ + if (max > 9) + max = 9; + + /* + * we "cheat" by converting the fractional part to integer by multiplying + * by a factor of 10 + */ + max10 = roundv(pow_10(max)); + fracpart = roundv(pow_10(max) * (ufvalue - intpart)); + + if (fracpart >= max10) { + intpart++; + fracpart -= max10; + } + + /* convert integer part */ + do { + iconvert[iplace++] = "0123456789"[intpart % 10]; + intpart = (intpart / 10); + } while (intpart && (iplace < (int)sizeof(iconvert))); + if (iplace == sizeof(iconvert)) + iplace--; + iconvert[iplace] = 0; + + /* convert fractional part */ + while (fplace < max) { + if (style == G_FORMAT && fplace == 0 && (fracpart % 10) == 0) { + /* We strip trailing zeros in G_FORMAT */ + max--; + fracpart = fracpart / 10; + if (fplace < max) + continue; + break; + } + fconvert[fplace++] = "0123456789"[fracpart % 10]; + fracpart = (fracpart / 10); + } + + if (fplace == sizeof(fconvert)) + fplace--; + fconvert[fplace] = 0; + + /* convert exponent part */ + if (realstyle == E_FORMAT) { + int tmpexp; + if (exp < 0) + tmpexp = -exp; + else + tmpexp = exp; + + do { + econvert[eplace++] = "0123456789"[tmpexp % 10]; + tmpexp = (tmpexp / 10); + } while (tmpexp > 0 && eplace < (int)sizeof(econvert)); + /* Exponent is huge!! Too big to print */ + if (tmpexp > 0) + return 0; + /* Add a leading 0 for single digit exponents */ + if (eplace == 1) + econvert[eplace++] = '0'; + } + + /* + * -1 for decimal point (if we have one, i.e. max > 0), + * another -1 if we are printing a sign + */ + padlen = min - iplace - max - (max > 0 ? 1 : 0) - ((signvalue) ? 1 : 0); + /* Take some off for exponent prefix "+e" and exponent */ + if (realstyle == E_FORMAT) + padlen -= 2 + eplace; + zpadlen = max - fplace; + if (zpadlen < 0) + zpadlen = 0; + if (padlen < 0) + padlen = 0; + if (flags & DP_F_MINUS) + padlen = -padlen; + + if ((flags & DP_F_ZERO) && (padlen > 0)) { + if (signvalue) { + if (!doapr_outch(sbuffer, buffer, currlen, maxlen, signvalue)) + return 0; + --padlen; + signvalue = 0; + } + while (padlen > 0) { + if (!doapr_outch(sbuffer, buffer, currlen, maxlen, '0')) + return 0; + --padlen; + } + } + while (padlen > 0) { + if (!doapr_outch(sbuffer, buffer, currlen, maxlen, ' ')) + return 0; + --padlen; + } + if (signvalue && !doapr_outch(sbuffer, buffer, currlen, maxlen, signvalue)) + return 0; + + while (iplace > 0) { + if (!doapr_outch(sbuffer, buffer, currlen, maxlen, iconvert[--iplace])) + return 0; + } + + /* + * Decimal point. This should probably use locale to find the correct + * char to print out. + */ + if (max > 0 || (flags & DP_F_NUM)) { + if (!doapr_outch(sbuffer, buffer, currlen, maxlen, '.')) + return 0; + + while (fplace > 0) { + if (!doapr_outch(sbuffer, buffer, currlen, maxlen, + fconvert[--fplace])) + return 0; + } + } + while (zpadlen > 0) { + if (!doapr_outch(sbuffer, buffer, currlen, maxlen, '0')) + return 0; + --zpadlen; + } + if (realstyle == E_FORMAT) { + char ech; + + if ((flags & DP_F_UP) == 0) + ech = 'e'; + else + ech = 'E'; + if (!doapr_outch(sbuffer, buffer, currlen, maxlen, ech)) + return 0; + if (exp < 0) { + if (!doapr_outch(sbuffer, buffer, currlen, maxlen, '-')) + return 0; + } else { + if (!doapr_outch(sbuffer, buffer, currlen, maxlen, '+')) + return 0; + } + while (eplace > 0) { + if (!doapr_outch(sbuffer, buffer, currlen, maxlen, + econvert[--eplace])) + return 0; + } + } + + while (padlen < 0) { + if (!doapr_outch(sbuffer, buffer, currlen, maxlen, ' ')) + return 0; + ++padlen; + } + return 1; +} + +#define BUFFER_INC 1024 + +static int +doapr_outch(char **sbuffer, + char **buffer, size_t *currlen, size_t *maxlen, int c) +{ + /* If we haven't at least one buffer, someone has done a big booboo */ + if (!ossl_assert(*sbuffer != NULL || buffer != NULL)) + return 0; + + /* |currlen| must always be <= |*maxlen| */ + if (!ossl_assert(*currlen <= *maxlen)) + return 0; + + if (buffer && *currlen == *maxlen) { + if (*maxlen > INT_MAX - BUFFER_INC) + return 0; + + *maxlen += BUFFER_INC; + if (*buffer == NULL) { + if ((*buffer = OPENSSL_malloc(*maxlen)) == NULL) { + BIOerr(BIO_F_DOAPR_OUTCH, ERR_R_MALLOC_FAILURE); + return 0; + } + if (*currlen > 0) { + if (!ossl_assert(*sbuffer != NULL)) + return 0; + memcpy(*buffer, *sbuffer, *currlen); + } + *sbuffer = NULL; + } else { + char *tmpbuf; + tmpbuf = OPENSSL_realloc(*buffer, *maxlen); + if (tmpbuf == NULL) + return 0; + *buffer = tmpbuf; + } + } + + if (*currlen < *maxlen) { + if (*sbuffer) + (*sbuffer)[(*currlen)++] = (char)c; + else + (*buffer)[(*currlen)++] = (char)c; + } + + return 1; +} + +/***************************************************************************/ + +int BIO_printf(BIO *bio, const char *format, ...) +{ + va_list args; + int ret; + + va_start(args, format); + + ret = BIO_vprintf(bio, format, args); + + va_end(args); + return ret; +} + +int BIO_vprintf(BIO *bio, const char *format, va_list args) +{ + int ret; + size_t retlen; + char hugebuf[1024 * 2]; /* Was previously 10k, which is unreasonable + * in small-stack environments, like threads + * or DOS programs. */ + char *hugebufp = hugebuf; + size_t hugebufsize = sizeof(hugebuf); + char *dynbuf = NULL; + int ignored; + + dynbuf = NULL; + if (!_dopr(&hugebufp, &dynbuf, &hugebufsize, &retlen, &ignored, format, + args)) { + OPENSSL_free(dynbuf); + return -1; + } + if (dynbuf) { + ret = BIO_write(bio, dynbuf, (int)retlen); + OPENSSL_free(dynbuf); + } else { + ret = BIO_write(bio, hugebuf, (int)retlen); + } + return ret; +} + +/* + * As snprintf is not available everywhere, we provide our own + * implementation. This function has nothing to do with BIOs, but it's + * closely related to BIO_printf, and we need *some* name prefix ... (XXX the + * function should be renamed, but to what?) + */ +int BIO_snprintf(char *buf, size_t n, const char *format, ...) +{ + va_list args; + int ret; + + va_start(args, format); + + ret = BIO_vsnprintf(buf, n, format, args); + + va_end(args); + return ret; +} + +int BIO_vsnprintf(char *buf, size_t n, const char *format, va_list args) +{ + size_t retlen; + int truncated; + + if (!_dopr(&buf, NULL, &n, &retlen, &truncated, format, args)) + return -1; + + if (truncated) + /* + * In case of truncation, return -1 like traditional snprintf. + * (Current drafts for ISO/IEC 9899 say snprintf should return the + * number of characters that would have been written, had the buffer + * been large enough.) + */ + return -1; + else + return (retlen <= INT_MAX) ? (int)retlen : -1; +} diff --git a/roms/edk2/CryptoPkg/Library/OpensslLib/openssl/crypto/bio/b_sock.c b/roms/edk2/CryptoPkg/Library/OpensslLib/openssl/crypto/bio/b_sock.c new file mode 100644 index 000000000..df431e6d5 --- /dev/null +++ b/roms/edk2/CryptoPkg/Library/OpensslLib/openssl/crypto/bio/b_sock.c @@ -0,0 +1,369 @@ +/* + * Copyright 1995-2018 The OpenSSL Project Authors. All Rights Reserved. + * + * Licensed under the OpenSSL license (the "License"). You may not use + * this file except in compliance with the License. You can obtain a copy + * in the file LICENSE in the source distribution or at + * https://www.openssl.org/source/license.html + */ + +#include <stdio.h> +#include <stdlib.h> +#include <errno.h> +#include "bio_local.h" +#ifndef OPENSSL_NO_SOCK +# define SOCKET_PROTOCOL IPPROTO_TCP +# ifdef SO_MAXCONN +# define MAX_LISTEN SO_MAXCONN +# elif defined(SOMAXCONN) +# define MAX_LISTEN SOMAXCONN +# else +# define MAX_LISTEN 32 +# endif +# if defined(OPENSSL_SYS_WINDOWS) +static int wsa_init_done = 0; +# endif + +# if OPENSSL_API_COMPAT < 0x10100000L +int BIO_get_host_ip(const char *str, unsigned char *ip) +{ + BIO_ADDRINFO *res = NULL; + int ret = 0; + + if (BIO_sock_init() != 1) + return 0; /* don't generate another error code here */ + + if (BIO_lookup(str, NULL, BIO_LOOKUP_CLIENT, AF_INET, SOCK_STREAM, &res)) { + size_t l; + + if (BIO_ADDRINFO_family(res) != AF_INET) { + BIOerr(BIO_F_BIO_GET_HOST_IP, + BIO_R_GETHOSTBYNAME_ADDR_IS_NOT_AF_INET); + } else if (BIO_ADDR_rawaddress(BIO_ADDRINFO_address(res), NULL, &l)) { + /* + * Because only AF_INET addresses will reach this far, we can assert + * that l should be 4 + */ + if (ossl_assert(l == 4)) + ret = BIO_ADDR_rawaddress(BIO_ADDRINFO_address(res), ip, &l); + } + BIO_ADDRINFO_free(res); + } else { + ERR_add_error_data(2, "host=", str); + } + + return ret; +} + +int BIO_get_port(const char *str, unsigned short *port_ptr) +{ + BIO_ADDRINFO *res = NULL; + int ret = 0; + + if (str == NULL) { + BIOerr(BIO_F_BIO_GET_PORT, BIO_R_NO_PORT_DEFINED); + return 0; + } + + if (BIO_sock_init() != 1) + return 0; /* don't generate another error code here */ + + if (BIO_lookup(NULL, str, BIO_LOOKUP_CLIENT, AF_INET, SOCK_STREAM, &res)) { + if (BIO_ADDRINFO_family(res) != AF_INET) { + BIOerr(BIO_F_BIO_GET_PORT, + BIO_R_ADDRINFO_ADDR_IS_NOT_AF_INET); + } else { + *port_ptr = ntohs(BIO_ADDR_rawport(BIO_ADDRINFO_address(res))); + ret = 1; + } + BIO_ADDRINFO_free(res); + } else { + ERR_add_error_data(2, "host=", str); + } + + return ret; +} +# endif + +int BIO_sock_error(int sock) +{ + int j = 0, i; + socklen_t size = sizeof(j); + + /* + * Note: under Windows the third parameter is of type (char *) whereas + * under other systems it is (void *) if you don't have a cast it will + * choke the compiler: if you do have a cast then you can either go for + * (char *) or (void *). + */ + i = getsockopt(sock, SOL_SOCKET, SO_ERROR, (void *)&j, &size); + if (i < 0) + return get_last_socket_error(); + else + return j; +} + +# if OPENSSL_API_COMPAT < 0x10100000L +struct hostent *BIO_gethostbyname(const char *name) +{ + /* + * Caching gethostbyname() results forever is wrong, so we have to let + * the true gethostbyname() worry about this + */ + return gethostbyname(name); +} +# endif + +int BIO_sock_init(void) +{ +# ifdef OPENSSL_SYS_WINDOWS + static struct WSAData wsa_state; + + if (!wsa_init_done) { + int err; + + wsa_init_done = 1; + memset(&wsa_state, 0, sizeof(wsa_state)); + /* + * Not making wsa_state available to the rest of the code is formally + * wrong. But the structures we use are [believed to be] invariable + * among Winsock DLLs, while API availability is [expected to be] + * probed at run-time with DSO_global_lookup. + */ + if (WSAStartup(0x0202, &wsa_state) != 0) { + err = WSAGetLastError(); + SYSerr(SYS_F_WSASTARTUP, err); + BIOerr(BIO_F_BIO_SOCK_INIT, BIO_R_WSASTARTUP); + return -1; + } + } +# endif /* OPENSSL_SYS_WINDOWS */ +# ifdef WATT32 + extern int _watt_do_exit; + _watt_do_exit = 0; /* don't make sock_init() call exit() */ + if (sock_init()) + return -1; +# endif + + return 1; +} + +void bio_sock_cleanup_int(void) +{ +# ifdef OPENSSL_SYS_WINDOWS + if (wsa_init_done) { + wsa_init_done = 0; + WSACleanup(); + } +# endif +} + +int BIO_socket_ioctl(int fd, long type, void *arg) +{ + int i; + +# ifdef __DJGPP__ + i = ioctlsocket(fd, type, (char *)arg); +# else +# if defined(OPENSSL_SYS_VMS) + /*- + * 2011-02-18 SMS. + * VMS ioctl() can't tolerate a 64-bit "void *arg", but we + * observe that all the consumers pass in an "unsigned long *", + * so we arrange a local copy with a short pointer, and use + * that, instead. + */ +# if __INITIAL_POINTER_SIZE == 64 +# define ARG arg_32p +# pragma pointer_size save +# pragma pointer_size 32 + unsigned long arg_32; + unsigned long *arg_32p; +# pragma pointer_size restore + arg_32p = &arg_32; + arg_32 = *((unsigned long *)arg); +# else /* __INITIAL_POINTER_SIZE == 64 */ +# define ARG arg +# endif /* __INITIAL_POINTER_SIZE == 64 [else] */ +# else /* defined(OPENSSL_SYS_VMS) */ +# define ARG arg +# endif /* defined(OPENSSL_SYS_VMS) [else] */ + + i = ioctlsocket(fd, type, ARG); +# endif /* __DJGPP__ */ + if (i < 0) + SYSerr(SYS_F_IOCTLSOCKET, get_last_socket_error()); + return i; +} + +# if OPENSSL_API_COMPAT < 0x10100000L +int BIO_get_accept_socket(char *host, int bind_mode) +{ + int s = INVALID_SOCKET; + char *h = NULL, *p = NULL; + BIO_ADDRINFO *res = NULL; + + if (!BIO_parse_hostserv(host, &h, &p, BIO_PARSE_PRIO_SERV)) + return INVALID_SOCKET; + + if (BIO_sock_init() != 1) + return INVALID_SOCKET; + + if (BIO_lookup(h, p, BIO_LOOKUP_SERVER, AF_UNSPEC, SOCK_STREAM, &res) != 0) + goto err; + + if ((s = BIO_socket(BIO_ADDRINFO_family(res), BIO_ADDRINFO_socktype(res), + BIO_ADDRINFO_protocol(res), 0)) == INVALID_SOCKET) { + s = INVALID_SOCKET; + goto err; + } + + if (!BIO_listen(s, BIO_ADDRINFO_address(res), + bind_mode ? BIO_SOCK_REUSEADDR : 0)) { + BIO_closesocket(s); + s = INVALID_SOCKET; + } + + err: + BIO_ADDRINFO_free(res); + OPENSSL_free(h); + OPENSSL_free(p); + + return s; +} + +int BIO_accept(int sock, char **ip_port) +{ + BIO_ADDR res; + int ret = -1; + + ret = BIO_accept_ex(sock, &res, 0); + if (ret == (int)INVALID_SOCKET) { + if (BIO_sock_should_retry(ret)) { + ret = -2; + goto end; + } + SYSerr(SYS_F_ACCEPT, get_last_socket_error()); + BIOerr(BIO_F_BIO_ACCEPT, BIO_R_ACCEPT_ERROR); + goto end; + } + + if (ip_port != NULL) { + char *host = BIO_ADDR_hostname_string(&res, 1); + char *port = BIO_ADDR_service_string(&res, 1); + if (host != NULL && port != NULL) + *ip_port = OPENSSL_zalloc(strlen(host) + strlen(port) + 2); + else + *ip_port = NULL; + + if (*ip_port == NULL) { + BIOerr(BIO_F_BIO_ACCEPT, ERR_R_MALLOC_FAILURE); + BIO_closesocket(ret); + ret = (int)INVALID_SOCKET; + } else { + strcpy(*ip_port, host); + strcat(*ip_port, ":"); + strcat(*ip_port, port); + } + OPENSSL_free(host); + OPENSSL_free(port); + } + + end: + return ret; +} +# endif + +int BIO_set_tcp_ndelay(int s, int on) +{ + int ret = 0; +# if defined(TCP_NODELAY) && (defined(IPPROTO_TCP) || defined(SOL_TCP)) + int opt; + +# ifdef SOL_TCP + opt = SOL_TCP; +# else +# ifdef IPPROTO_TCP + opt = IPPROTO_TCP; +# endif +# endif + + ret = setsockopt(s, opt, TCP_NODELAY, (char *)&on, sizeof(on)); +# endif + return (ret == 0); +} + +int BIO_socket_nbio(int s, int mode) +{ + int ret = -1; + int l; + + l = mode; +# ifdef FIONBIO + l = mode; + + ret = BIO_socket_ioctl(s, FIONBIO, &l); +# elif defined(F_GETFL) && defined(F_SETFL) && (defined(O_NONBLOCK) || defined(FNDELAY)) + /* make sure this call always pushes an error level; BIO_socket_ioctl() does so, so we do too. */ + + l = fcntl(s, F_GETFL, 0); + if (l == -1) { + SYSerr(SYS_F_FCNTL, get_last_sys_error()); + ret = -1; + } else { +# if defined(O_NONBLOCK) + l &= ~O_NONBLOCK; +# else + l &= ~FNDELAY; /* BSD4.x */ +# endif + if (mode) { +# if defined(O_NONBLOCK) + l |= O_NONBLOCK; +# else + l |= FNDELAY; /* BSD4.x */ +# endif + } + ret = fcntl(s, F_SETFL, l); + + if (ret < 0) { + SYSerr(SYS_F_FCNTL, get_last_sys_error()); + } + } +# else + /* make sure this call always pushes an error level; BIO_socket_ioctl() does so, so we do too. */ + BIOerr(BIO_F_BIO_SOCKET_NBIO, ERR_R_PASSED_INVALID_ARGUMENT); +# endif + + return (ret == 0); +} + +int BIO_sock_info(int sock, + enum BIO_sock_info_type type, union BIO_sock_info_u *info) +{ + switch (type) { + case BIO_SOCK_INFO_ADDRESS: + { + socklen_t addr_len; + int ret = 0; + addr_len = sizeof(*info->addr); + ret = getsockname(sock, BIO_ADDR_sockaddr_noconst(info->addr), + &addr_len); + if (ret == -1) { + SYSerr(SYS_F_GETSOCKNAME, get_last_socket_error()); + BIOerr(BIO_F_BIO_SOCK_INFO, BIO_R_GETSOCKNAME_ERROR); + return 0; + } + if ((size_t)addr_len > sizeof(*info->addr)) { + BIOerr(BIO_F_BIO_SOCK_INFO, BIO_R_GETSOCKNAME_TRUNCATED_ADDRESS); + return 0; + } + } + break; + default: + BIOerr(BIO_F_BIO_SOCK_INFO, BIO_R_UNKNOWN_INFO_TYPE); + return 0; + } + return 1; +} + +#endif diff --git a/roms/edk2/CryptoPkg/Library/OpensslLib/openssl/crypto/bio/b_sock2.c b/roms/edk2/CryptoPkg/Library/OpensslLib/openssl/crypto/bio/b_sock2.c new file mode 100644 index 000000000..335dfabc6 --- /dev/null +++ b/roms/edk2/CryptoPkg/Library/OpensslLib/openssl/crypto/bio/b_sock2.c @@ -0,0 +1,317 @@ +/* + * Copyright 2016-2018 The OpenSSL Project Authors. All Rights Reserved. + * + * Licensed under the OpenSSL license (the "License"). You may not use + * this file except in compliance with the License. You can obtain a copy + * in the file LICENSE in the source distribution or at + * https://www.openssl.org/source/license.html + */ + +#include <stdio.h> +#include <stdlib.h> +#include <errno.h> + +#include "bio_local.h" + +#include <openssl/err.h> + +#ifndef OPENSSL_NO_SOCK +# ifdef SO_MAXCONN +# define MAX_LISTEN SO_MAXCONN +# elif defined(SOMAXCONN) +# define MAX_LISTEN SOMAXCONN +# else +# define MAX_LISTEN 32 +# endif + +/*- + * BIO_socket - create a socket + * @domain: the socket domain (AF_INET, AF_INET6, AF_UNIX, ...) + * @socktype: the socket type (SOCK_STEAM, SOCK_DGRAM) + * @protocol: the protocol to use (IPPROTO_TCP, IPPROTO_UDP) + * @options: BIO socket options (currently unused) + * + * Creates a socket. This should be called before calling any + * of BIO_connect and BIO_listen. + * + * Returns the file descriptor on success or INVALID_SOCKET on failure. On + * failure errno is set, and a status is added to the OpenSSL error stack. + */ +int BIO_socket(int domain, int socktype, int protocol, int options) +{ + int sock = -1; + + if (BIO_sock_init() != 1) + return INVALID_SOCKET; + + sock = socket(domain, socktype, protocol); + if (sock == -1) { + SYSerr(SYS_F_SOCKET, get_last_socket_error()); + BIOerr(BIO_F_BIO_SOCKET, BIO_R_UNABLE_TO_CREATE_SOCKET); + return INVALID_SOCKET; + } + + return sock; +} + +/*- + * BIO_connect - connect to an address + * @sock: the socket to connect with + * @addr: the address to connect to + * @options: BIO socket options + * + * Connects to the address using the given socket and options. + * + * Options can be a combination of the following: + * - BIO_SOCK_KEEPALIVE: enable regularly sending keep-alive messages. + * - BIO_SOCK_NONBLOCK: Make the socket non-blocking. + * - BIO_SOCK_NODELAY: don't delay small messages. + * + * options holds BIO socket options that can be used + * You should call this for every address returned by BIO_lookup + * until the connection is successful. + * + * Returns 1 on success or 0 on failure. On failure errno is set + * and an error status is added to the OpenSSL error stack. + */ +int BIO_connect(int sock, const BIO_ADDR *addr, int options) +{ + const int on = 1; + + if (sock == -1) { + BIOerr(BIO_F_BIO_CONNECT, BIO_R_INVALID_SOCKET); + return 0; + } + + if (!BIO_socket_nbio(sock, (options & BIO_SOCK_NONBLOCK) != 0)) + return 0; + + if (options & BIO_SOCK_KEEPALIVE) { + if (setsockopt(sock, SOL_SOCKET, SO_KEEPALIVE, + (const void *)&on, sizeof(on)) != 0) { + SYSerr(SYS_F_SETSOCKOPT, get_last_socket_error()); + BIOerr(BIO_F_BIO_CONNECT, BIO_R_UNABLE_TO_KEEPALIVE); + return 0; + } + } + + if (options & BIO_SOCK_NODELAY) { + if (setsockopt(sock, IPPROTO_TCP, TCP_NODELAY, + (const void *)&on, sizeof(on)) != 0) { + SYSerr(SYS_F_SETSOCKOPT, get_last_socket_error()); + BIOerr(BIO_F_BIO_CONNECT, BIO_R_UNABLE_TO_NODELAY); + return 0; + } + } + + if (connect(sock, BIO_ADDR_sockaddr(addr), + BIO_ADDR_sockaddr_size(addr)) == -1) { + if (!BIO_sock_should_retry(-1)) { + SYSerr(SYS_F_CONNECT, get_last_socket_error()); + BIOerr(BIO_F_BIO_CONNECT, BIO_R_CONNECT_ERROR); + } + return 0; + } + return 1; +} + +/*- + * BIO_bind - bind socket to address + * @sock: the socket to set + * @addr: local address to bind to + * @options: BIO socket options + * + * Binds to the address using the given socket and options. + * + * Options can be a combination of the following: + * - BIO_SOCK_REUSEADDR: Try to reuse the address and port combination + * for a recently closed port. + * + * When restarting the program it could be that the port is still in use. If + * you set to BIO_SOCK_REUSEADDR option it will try to reuse the port anyway. + * It's recommended that you use this. + */ +int BIO_bind(int sock, const BIO_ADDR *addr, int options) +{ +# ifndef OPENSSL_SYS_WINDOWS + int on = 1; +# endif + + if (sock == -1) { + BIOerr(BIO_F_BIO_BIND, BIO_R_INVALID_SOCKET); + return 0; + } + +# ifndef OPENSSL_SYS_WINDOWS + /* + * SO_REUSEADDR has different behavior on Windows than on + * other operating systems, don't set it there. + */ + if (options & BIO_SOCK_REUSEADDR) { + if (setsockopt(sock, SOL_SOCKET, SO_REUSEADDR, + (const void *)&on, sizeof(on)) != 0) { + SYSerr(SYS_F_SETSOCKOPT, get_last_socket_error()); + BIOerr(BIO_F_BIO_BIND, BIO_R_UNABLE_TO_REUSEADDR); + return 0; + } + } +# endif + + if (bind(sock, BIO_ADDR_sockaddr(addr), BIO_ADDR_sockaddr_size(addr)) != 0) { + SYSerr(SYS_F_BIND, get_last_socket_error()); + BIOerr(BIO_F_BIO_BIND, BIO_R_UNABLE_TO_BIND_SOCKET); + return 0; + } + + return 1; +} + +/*- + * BIO_listen - Creates a listen socket + * @sock: the socket to listen with + * @addr: local address to bind to + * @options: BIO socket options + * + * Binds to the address using the given socket and options, then + * starts listening for incoming connections. + * + * Options can be a combination of the following: + * - BIO_SOCK_KEEPALIVE: enable regularly sending keep-alive messages. + * - BIO_SOCK_NONBLOCK: Make the socket non-blocking. + * - BIO_SOCK_NODELAY: don't delay small messages. + * - BIO_SOCK_REUSEADDR: Try to reuse the address and port combination + * for a recently closed port. + * - BIO_SOCK_V6_ONLY: When creating an IPv6 socket, make it listen only + * for IPv6 addresses and not IPv4 addresses mapped to IPv6. + * + * It's recommended that you set up both an IPv6 and IPv4 listen socket, and + * then check both for new clients that connect to it. You want to set up + * the socket as non-blocking in that case since else it could hang. + * + * Not all operating systems support IPv4 addresses on an IPv6 socket, and for + * others it's an option. If you pass the BIO_LISTEN_V6_ONLY it will try to + * create the IPv6 sockets to only listen for IPv6 connection. + * + * It could be that the first BIO_listen() call will listen to all the IPv6 + * and IPv4 addresses and that then trying to bind to the IPv4 address will + * fail. We can't tell the difference between already listening ourself to + * it and someone else listening to it when failing and errno is EADDRINUSE, so + * it's recommended to not give an error in that case if the first call was + * successful. + * + * When restarting the program it could be that the port is still in use. If + * you set to BIO_SOCK_REUSEADDR option it will try to reuse the port anyway. + * It's recommended that you use this. + */ +int BIO_listen(int sock, const BIO_ADDR *addr, int options) +{ + int on = 1; + int socktype; + socklen_t socktype_len = sizeof(socktype); + + if (sock == -1) { + BIOerr(BIO_F_BIO_LISTEN, BIO_R_INVALID_SOCKET); + return 0; + } + + if (getsockopt(sock, SOL_SOCKET, SO_TYPE, + (void *)&socktype, &socktype_len) != 0 + || socktype_len != sizeof(socktype)) { + SYSerr(SYS_F_GETSOCKOPT, get_last_socket_error()); + BIOerr(BIO_F_BIO_LISTEN, BIO_R_GETTING_SOCKTYPE); + return 0; + } + + if (!BIO_socket_nbio(sock, (options & BIO_SOCK_NONBLOCK) != 0)) + return 0; + + if (options & BIO_SOCK_KEEPALIVE) { + if (setsockopt(sock, SOL_SOCKET, SO_KEEPALIVE, + (const void *)&on, sizeof(on)) != 0) { + SYSerr(SYS_F_SETSOCKOPT, get_last_socket_error()); + BIOerr(BIO_F_BIO_LISTEN, BIO_R_UNABLE_TO_KEEPALIVE); + return 0; + } + } + + if (options & BIO_SOCK_NODELAY) { + if (setsockopt(sock, IPPROTO_TCP, TCP_NODELAY, + (const void *)&on, sizeof(on)) != 0) { + SYSerr(SYS_F_SETSOCKOPT, get_last_socket_error()); + BIOerr(BIO_F_BIO_LISTEN, BIO_R_UNABLE_TO_NODELAY); + return 0; + } + } + +# ifdef IPV6_V6ONLY + if (BIO_ADDR_family(addr) == AF_INET6) { + /* + * Note: Windows default of IPV6_V6ONLY is ON, and Linux is OFF. + * Therefore we always have to use setsockopt here. + */ + on = options & BIO_SOCK_V6_ONLY ? 1 : 0; + if (setsockopt(sock, IPPROTO_IPV6, IPV6_V6ONLY, + (const void *)&on, sizeof(on)) != 0) { + SYSerr(SYS_F_SETSOCKOPT, get_last_socket_error()); + BIOerr(BIO_F_BIO_LISTEN, BIO_R_LISTEN_V6_ONLY); + return 0; + } + } +# endif + + if (!BIO_bind(sock, addr, options)) + return 0; + + if (socktype != SOCK_DGRAM && listen(sock, MAX_LISTEN) == -1) { + SYSerr(SYS_F_LISTEN, get_last_socket_error()); + BIOerr(BIO_F_BIO_LISTEN, BIO_R_UNABLE_TO_LISTEN_SOCKET); + return 0; + } + + return 1; +} + +/*- + * BIO_accept_ex - Accept new incoming connections + * @sock: the listening socket + * @addr: the BIO_ADDR to store the peer address in + * @options: BIO socket options, applied on the accepted socket. + * + */ +int BIO_accept_ex(int accept_sock, BIO_ADDR *addr_, int options) +{ + socklen_t len; + int accepted_sock; + BIO_ADDR locaddr; + BIO_ADDR *addr = addr_ == NULL ? &locaddr : addr_; + + len = sizeof(*addr); + accepted_sock = accept(accept_sock, + BIO_ADDR_sockaddr_noconst(addr), &len); + if (accepted_sock == -1) { + if (!BIO_sock_should_retry(accepted_sock)) { + SYSerr(SYS_F_ACCEPT, get_last_socket_error()); + BIOerr(BIO_F_BIO_ACCEPT_EX, BIO_R_ACCEPT_ERROR); + } + return INVALID_SOCKET; + } + + if (!BIO_socket_nbio(accepted_sock, (options & BIO_SOCK_NONBLOCK) != 0)) { + closesocket(accepted_sock); + return INVALID_SOCKET; + } + + return accepted_sock; +} + +/*- + * BIO_closesocket - Close a socket + * @sock: the socket to close + */ +int BIO_closesocket(int sock) +{ + if (closesocket(sock) < 0) + return 0; + return 1; +} +#endif diff --git a/roms/edk2/CryptoPkg/Library/OpensslLib/openssl/crypto/bio/bf_buff.c b/roms/edk2/CryptoPkg/Library/OpensslLib/openssl/crypto/bio/bf_buff.c new file mode 100644 index 000000000..51ae1f918 --- /dev/null +++ b/roms/edk2/CryptoPkg/Library/OpensslLib/openssl/crypto/bio/bf_buff.c @@ -0,0 +1,475 @@ +/* + * Copyright 1995-2016 The OpenSSL Project Authors. All Rights Reserved. + * + * Licensed under the OpenSSL license (the "License"). You may not use + * this file except in compliance with the License. You can obtain a copy + * in the file LICENSE in the source distribution or at + * https://www.openssl.org/source/license.html + */ + +#include <stdio.h> +#include <errno.h> +#include "bio_local.h" +#include "internal/cryptlib.h" + +static int buffer_write(BIO *h, const char *buf, int num); +static int buffer_read(BIO *h, char *buf, int size); +static int buffer_puts(BIO *h, const char *str); +static int buffer_gets(BIO *h, char *str, int size); +static long buffer_ctrl(BIO *h, int cmd, long arg1, void *arg2); +static int buffer_new(BIO *h); +static int buffer_free(BIO *data); +static long buffer_callback_ctrl(BIO *h, int cmd, BIO_info_cb *fp); +#define DEFAULT_BUFFER_SIZE 4096 + +static const BIO_METHOD methods_buffer = { + BIO_TYPE_BUFFER, + "buffer", + /* TODO: Convert to new style write function */ + bwrite_conv, + buffer_write, + /* TODO: Convert to new style read function */ + bread_conv, + buffer_read, + buffer_puts, + buffer_gets, + buffer_ctrl, + buffer_new, + buffer_free, + buffer_callback_ctrl, +}; + +const BIO_METHOD *BIO_f_buffer(void) +{ + return &methods_buffer; +} + +static int buffer_new(BIO *bi) +{ + BIO_F_BUFFER_CTX *ctx = OPENSSL_zalloc(sizeof(*ctx)); + + if (ctx == NULL) + return 0; + ctx->ibuf_size = DEFAULT_BUFFER_SIZE; + ctx->ibuf = OPENSSL_malloc(DEFAULT_BUFFER_SIZE); + if (ctx->ibuf == NULL) { + OPENSSL_free(ctx); + return 0; + } + ctx->obuf_size = DEFAULT_BUFFER_SIZE; + ctx->obuf = OPENSSL_malloc(DEFAULT_BUFFER_SIZE); + if (ctx->obuf == NULL) { + OPENSSL_free(ctx->ibuf); + OPENSSL_free(ctx); + return 0; + } + + bi->init = 1; + bi->ptr = (char *)ctx; + bi->flags = 0; + return 1; +} + +static int buffer_free(BIO *a) +{ + BIO_F_BUFFER_CTX *b; + + if (a == NULL) + return 0; + b = (BIO_F_BUFFER_CTX *)a->ptr; + OPENSSL_free(b->ibuf); + OPENSSL_free(b->obuf); + OPENSSL_free(a->ptr); + a->ptr = NULL; + a->init = 0; + a->flags = 0; + return 1; +} + +static int buffer_read(BIO *b, char *out, int outl) +{ + int i, num = 0; + BIO_F_BUFFER_CTX *ctx; + + if (out == NULL) + return 0; + ctx = (BIO_F_BUFFER_CTX *)b->ptr; + + if ((ctx == NULL) || (b->next_bio == NULL)) + return 0; + num = 0; + BIO_clear_retry_flags(b); + + start: + i = ctx->ibuf_len; + /* If there is stuff left over, grab it */ + if (i != 0) { + if (i > outl) + i = outl; + memcpy(out, &(ctx->ibuf[ctx->ibuf_off]), i); + ctx->ibuf_off += i; + ctx->ibuf_len -= i; + num += i; + if (outl == i) + return num; + outl -= i; + out += i; + } + + /* + * We may have done a partial read. try to do more. We have nothing in + * the buffer. If we get an error and have read some data, just return it + * and let them retry to get the error again. copy direct to parent + * address space + */ + if (outl > ctx->ibuf_size) { + for (;;) { + i = BIO_read(b->next_bio, out, outl); + if (i <= 0) { + BIO_copy_next_retry(b); + if (i < 0) + return ((num > 0) ? num : i); + if (i == 0) + return num; + } + num += i; + if (outl == i) + return num; + out += i; + outl -= i; + } + } + /* else */ + + /* we are going to be doing some buffering */ + i = BIO_read(b->next_bio, ctx->ibuf, ctx->ibuf_size); + if (i <= 0) { + BIO_copy_next_retry(b); + if (i < 0) + return ((num > 0) ? num : i); + if (i == 0) + return num; + } + ctx->ibuf_off = 0; + ctx->ibuf_len = i; + + /* Lets re-read using ourselves :-) */ + goto start; +} + +static int buffer_write(BIO *b, const char *in, int inl) +{ + int i, num = 0; + BIO_F_BUFFER_CTX *ctx; + + if ((in == NULL) || (inl <= 0)) + return 0; + ctx = (BIO_F_BUFFER_CTX *)b->ptr; + if ((ctx == NULL) || (b->next_bio == NULL)) + return 0; + + BIO_clear_retry_flags(b); + start: + i = ctx->obuf_size - (ctx->obuf_len + ctx->obuf_off); + /* add to buffer and return */ + if (i >= inl) { + memcpy(&(ctx->obuf[ctx->obuf_off + ctx->obuf_len]), in, inl); + ctx->obuf_len += inl; + return (num + inl); + } + /* else */ + /* stuff already in buffer, so add to it first, then flush */ + if (ctx->obuf_len != 0) { + if (i > 0) { /* lets fill it up if we can */ + memcpy(&(ctx->obuf[ctx->obuf_off + ctx->obuf_len]), in, i); + in += i; + inl -= i; + num += i; + ctx->obuf_len += i; + } + /* we now have a full buffer needing flushing */ + for (;;) { + i = BIO_write(b->next_bio, &(ctx->obuf[ctx->obuf_off]), + ctx->obuf_len); + if (i <= 0) { + BIO_copy_next_retry(b); + + if (i < 0) + return ((num > 0) ? num : i); + if (i == 0) + return num; + } + ctx->obuf_off += i; + ctx->obuf_len -= i; + if (ctx->obuf_len == 0) + break; + } + } + /* + * we only get here if the buffer has been flushed and we still have + * stuff to write + */ + ctx->obuf_off = 0; + + /* we now have inl bytes to write */ + while (inl >= ctx->obuf_size) { + i = BIO_write(b->next_bio, in, inl); + if (i <= 0) { + BIO_copy_next_retry(b); + if (i < 0) + return ((num > 0) ? num : i); + if (i == 0) + return num; + } + num += i; + in += i; + inl -= i; + if (inl == 0) + return num; + } + + /* + * copy the rest into the buffer since we have only a small amount left + */ + goto start; +} + +static long buffer_ctrl(BIO *b, int cmd, long num, void *ptr) +{ + BIO *dbio; + BIO_F_BUFFER_CTX *ctx; + long ret = 1; + char *p1, *p2; + int r, i, *ip; + int ibs, obs; + + ctx = (BIO_F_BUFFER_CTX *)b->ptr; + + switch (cmd) { + case BIO_CTRL_RESET: + ctx->ibuf_off = 0; + ctx->ibuf_len = 0; + ctx->obuf_off = 0; + ctx->obuf_len = 0; + if (b->next_bio == NULL) + return 0; + ret = BIO_ctrl(b->next_bio, cmd, num, ptr); + break; + case BIO_CTRL_EOF: + if (ctx->ibuf_len > 0) + return 0; + ret = BIO_ctrl(b->next_bio, cmd, num, ptr); + break; + case BIO_CTRL_INFO: + ret = (long)ctx->obuf_len; + break; + case BIO_C_GET_BUFF_NUM_LINES: + ret = 0; + p1 = ctx->ibuf; + for (i = 0; i < ctx->ibuf_len; i++) { + if (p1[ctx->ibuf_off + i] == '\n') + ret++; + } + break; + case BIO_CTRL_WPENDING: + ret = (long)ctx->obuf_len; + if (ret == 0) { + if (b->next_bio == NULL) + return 0; + ret = BIO_ctrl(b->next_bio, cmd, num, ptr); + } + break; + case BIO_CTRL_PENDING: + ret = (long)ctx->ibuf_len; + if (ret == 0) { + if (b->next_bio == NULL) + return 0; + ret = BIO_ctrl(b->next_bio, cmd, num, ptr); + } + break; + case BIO_C_SET_BUFF_READ_DATA: + if (num > ctx->ibuf_size) { + p1 = OPENSSL_malloc((int)num); + if (p1 == NULL) + goto malloc_error; + OPENSSL_free(ctx->ibuf); + ctx->ibuf = p1; + } + ctx->ibuf_off = 0; + ctx->ibuf_len = (int)num; + memcpy(ctx->ibuf, ptr, (int)num); + ret = 1; + break; + case BIO_C_SET_BUFF_SIZE: + if (ptr != NULL) { + ip = (int *)ptr; + if (*ip == 0) { + ibs = (int)num; + obs = ctx->obuf_size; + } else { /* if (*ip == 1) */ + + ibs = ctx->ibuf_size; + obs = (int)num; + } + } else { + ibs = (int)num; + obs = (int)num; + } + p1 = ctx->ibuf; + p2 = ctx->obuf; + if ((ibs > DEFAULT_BUFFER_SIZE) && (ibs != ctx->ibuf_size)) { + p1 = OPENSSL_malloc((int)num); + if (p1 == NULL) + goto malloc_error; + } + if ((obs > DEFAULT_BUFFER_SIZE) && (obs != ctx->obuf_size)) { + p2 = OPENSSL_malloc((int)num); + if (p2 == NULL) { + if (p1 != ctx->ibuf) + OPENSSL_free(p1); + goto malloc_error; + } + } + if (ctx->ibuf != p1) { + OPENSSL_free(ctx->ibuf); + ctx->ibuf = p1; + ctx->ibuf_off = 0; + ctx->ibuf_len = 0; + ctx->ibuf_size = ibs; + } + if (ctx->obuf != p2) { + OPENSSL_free(ctx->obuf); + ctx->obuf = p2; + ctx->obuf_off = 0; + ctx->obuf_len = 0; + ctx->obuf_size = obs; + } + break; + case BIO_C_DO_STATE_MACHINE: + if (b->next_bio == NULL) + return 0; + BIO_clear_retry_flags(b); + ret = BIO_ctrl(b->next_bio, cmd, num, ptr); + BIO_copy_next_retry(b); + break; + + case BIO_CTRL_FLUSH: + if (b->next_bio == NULL) + return 0; + if (ctx->obuf_len <= 0) { + ret = BIO_ctrl(b->next_bio, cmd, num, ptr); + break; + } + + for (;;) { + BIO_clear_retry_flags(b); + if (ctx->obuf_len > 0) { + r = BIO_write(b->next_bio, + &(ctx->obuf[ctx->obuf_off]), ctx->obuf_len); + BIO_copy_next_retry(b); + if (r <= 0) + return (long)r; + ctx->obuf_off += r; + ctx->obuf_len -= r; + } else { + ctx->obuf_len = 0; + ctx->obuf_off = 0; + break; + } + } + ret = BIO_ctrl(b->next_bio, cmd, num, ptr); + break; + case BIO_CTRL_DUP: + dbio = (BIO *)ptr; + if (!BIO_set_read_buffer_size(dbio, ctx->ibuf_size) || + !BIO_set_write_buffer_size(dbio, ctx->obuf_size)) + ret = 0; + break; + case BIO_CTRL_PEEK: + /* Ensure there's stuff in the input buffer */ + { + char fake_buf[1]; + (void)buffer_read(b, fake_buf, 0); + } + if (num > ctx->ibuf_len) + num = ctx->ibuf_len; + memcpy(ptr, &(ctx->ibuf[ctx->ibuf_off]), num); + ret = num; + break; + default: + if (b->next_bio == NULL) + return 0; + ret = BIO_ctrl(b->next_bio, cmd, num, ptr); + break; + } + return ret; + malloc_error: + BIOerr(BIO_F_BUFFER_CTRL, ERR_R_MALLOC_FAILURE); + return 0; +} + +static long buffer_callback_ctrl(BIO *b, int cmd, BIO_info_cb *fp) +{ + long ret = 1; + + if (b->next_bio == NULL) + return 0; + switch (cmd) { + default: + ret = BIO_callback_ctrl(b->next_bio, cmd, fp); + break; + } + return ret; +} + +static int buffer_gets(BIO *b, char *buf, int size) +{ + BIO_F_BUFFER_CTX *ctx; + int num = 0, i, flag; + char *p; + + ctx = (BIO_F_BUFFER_CTX *)b->ptr; + size--; /* reserve space for a '\0' */ + BIO_clear_retry_flags(b); + + for (;;) { + if (ctx->ibuf_len > 0) { + p = &(ctx->ibuf[ctx->ibuf_off]); + flag = 0; + for (i = 0; (i < ctx->ibuf_len) && (i < size); i++) { + *(buf++) = p[i]; + if (p[i] == '\n') { + flag = 1; + i++; + break; + } + } + num += i; + size -= i; + ctx->ibuf_len -= i; + ctx->ibuf_off += i; + if (flag || size == 0) { + *buf = '\0'; + return num; + } + } else { /* read another chunk */ + + i = BIO_read(b->next_bio, ctx->ibuf, ctx->ibuf_size); + if (i <= 0) { + BIO_copy_next_retry(b); + *buf = '\0'; + if (i < 0) + return ((num > 0) ? num : i); + if (i == 0) + return num; + } + ctx->ibuf_len = i; + ctx->ibuf_off = 0; + } + } +} + +static int buffer_puts(BIO *b, const char *str) +{ + return buffer_write(b, str, strlen(str)); +} diff --git a/roms/edk2/CryptoPkg/Library/OpensslLib/openssl/crypto/bio/bf_lbuf.c b/roms/edk2/CryptoPkg/Library/OpensslLib/openssl/crypto/bio/bf_lbuf.c new file mode 100644 index 000000000..72f990181 --- /dev/null +++ b/roms/edk2/CryptoPkg/Library/OpensslLib/openssl/crypto/bio/bf_lbuf.c @@ -0,0 +1,326 @@ +/* + * Copyright 1995-2018 The OpenSSL Project Authors. All Rights Reserved. + * + * Licensed under the OpenSSL license (the "License"). You may not use + * this file except in compliance with the License. You can obtain a copy + * in the file LICENSE in the source distribution or at + * https://www.openssl.org/source/license.html + */ + +#include <stdio.h> +#include <errno.h> +#include "bio_local.h" +#include "internal/cryptlib.h" +#include <openssl/evp.h> + +static int linebuffer_write(BIO *h, const char *buf, int num); +static int linebuffer_read(BIO *h, char *buf, int size); +static int linebuffer_puts(BIO *h, const char *str); +static int linebuffer_gets(BIO *h, char *str, int size); +static long linebuffer_ctrl(BIO *h, int cmd, long arg1, void *arg2); +static int linebuffer_new(BIO *h); +static int linebuffer_free(BIO *data); +static long linebuffer_callback_ctrl(BIO *h, int cmd, BIO_info_cb *fp); + +/* A 10k maximum should be enough for most purposes */ +#define DEFAULT_LINEBUFFER_SIZE 1024*10 + +/* #define DEBUG */ + +static const BIO_METHOD methods_linebuffer = { + BIO_TYPE_LINEBUFFER, + "linebuffer", + /* TODO: Convert to new style write function */ + bwrite_conv, + linebuffer_write, + /* TODO: Convert to new style read function */ + bread_conv, + linebuffer_read, + linebuffer_puts, + linebuffer_gets, + linebuffer_ctrl, + linebuffer_new, + linebuffer_free, + linebuffer_callback_ctrl, +}; + +const BIO_METHOD *BIO_f_linebuffer(void) +{ + return &methods_linebuffer; +} + +typedef struct bio_linebuffer_ctx_struct { + char *obuf; /* the output char array */ + int obuf_size; /* how big is the output buffer */ + int obuf_len; /* how many bytes are in it */ +} BIO_LINEBUFFER_CTX; + +static int linebuffer_new(BIO *bi) +{ + BIO_LINEBUFFER_CTX *ctx; + + if ((ctx = OPENSSL_malloc(sizeof(*ctx))) == NULL) { + BIOerr(BIO_F_LINEBUFFER_NEW, ERR_R_MALLOC_FAILURE); + return 0; + } + ctx->obuf = OPENSSL_malloc(DEFAULT_LINEBUFFER_SIZE); + if (ctx->obuf == NULL) { + BIOerr(BIO_F_LINEBUFFER_NEW, ERR_R_MALLOC_FAILURE); + OPENSSL_free(ctx); + return 0; + } + ctx->obuf_size = DEFAULT_LINEBUFFER_SIZE; + ctx->obuf_len = 0; + + bi->init = 1; + bi->ptr = (char *)ctx; + bi->flags = 0; + return 1; +} + +static int linebuffer_free(BIO *a) +{ + BIO_LINEBUFFER_CTX *b; + + if (a == NULL) + return 0; + b = (BIO_LINEBUFFER_CTX *)a->ptr; + OPENSSL_free(b->obuf); + OPENSSL_free(a->ptr); + a->ptr = NULL; + a->init = 0; + a->flags = 0; + return 1; +} + +static int linebuffer_read(BIO *b, char *out, int outl) +{ + int ret = 0; + + if (out == NULL) + return 0; + if (b->next_bio == NULL) + return 0; + ret = BIO_read(b->next_bio, out, outl); + BIO_clear_retry_flags(b); + BIO_copy_next_retry(b); + return ret; +} + +static int linebuffer_write(BIO *b, const char *in, int inl) +{ + int i, num = 0, foundnl; + BIO_LINEBUFFER_CTX *ctx; + + if ((in == NULL) || (inl <= 0)) + return 0; + ctx = (BIO_LINEBUFFER_CTX *)b->ptr; + if ((ctx == NULL) || (b->next_bio == NULL)) + return 0; + + BIO_clear_retry_flags(b); + + do { + const char *p; + char c; + + for (p = in, c = '\0'; p < in + inl && (c = *p) != '\n'; p++) ; + if (c == '\n') { + p++; + foundnl = 1; + } else + foundnl = 0; + + /* + * If a NL was found and we already have text in the save buffer, + * concatenate them and write + */ + while ((foundnl || p - in > ctx->obuf_size - ctx->obuf_len) + && ctx->obuf_len > 0) { + int orig_olen = ctx->obuf_len; + + i = ctx->obuf_size - ctx->obuf_len; + if (p - in > 0) { + if (i >= p - in) { + memcpy(&(ctx->obuf[ctx->obuf_len]), in, p - in); + ctx->obuf_len += p - in; + inl -= p - in; + num += p - in; + in = p; + } else { + memcpy(&(ctx->obuf[ctx->obuf_len]), in, i); + ctx->obuf_len += i; + inl -= i; + in += i; + num += i; + } + } + i = BIO_write(b->next_bio, ctx->obuf, ctx->obuf_len); + if (i <= 0) { + ctx->obuf_len = orig_olen; + BIO_copy_next_retry(b); + + if (i < 0) + return ((num > 0) ? num : i); + if (i == 0) + return num; + } + if (i < ctx->obuf_len) + memmove(ctx->obuf, ctx->obuf + i, ctx->obuf_len - i); + ctx->obuf_len -= i; + } + + /* + * Now that the save buffer is emptied, let's write the input buffer + * if a NL was found and there is anything to write. + */ + if ((foundnl || p - in > ctx->obuf_size) && p - in > 0) { + i = BIO_write(b->next_bio, in, p - in); + if (i <= 0) { + BIO_copy_next_retry(b); + if (i < 0) + return ((num > 0) ? num : i); + if (i == 0) + return num; + } + num += i; + in += i; + inl -= i; + } + } + while (foundnl && inl > 0); + /* + * We've written as much as we can. The rest of the input buffer, if + * any, is text that doesn't and with a NL and therefore needs to be + * saved for the next trip. + */ + if (inl > 0) { + memcpy(&(ctx->obuf[ctx->obuf_len]), in, inl); + ctx->obuf_len += inl; + num += inl; + } + return num; +} + +static long linebuffer_ctrl(BIO *b, int cmd, long num, void *ptr) +{ + BIO *dbio; + BIO_LINEBUFFER_CTX *ctx; + long ret = 1; + char *p; + int r; + int obs; + + ctx = (BIO_LINEBUFFER_CTX *)b->ptr; + + switch (cmd) { + case BIO_CTRL_RESET: + ctx->obuf_len = 0; + if (b->next_bio == NULL) + return 0; + ret = BIO_ctrl(b->next_bio, cmd, num, ptr); + break; + case BIO_CTRL_INFO: + ret = (long)ctx->obuf_len; + break; + case BIO_CTRL_WPENDING: + ret = (long)ctx->obuf_len; + if (ret == 0) { + if (b->next_bio == NULL) + return 0; + ret = BIO_ctrl(b->next_bio, cmd, num, ptr); + } + break; + case BIO_C_SET_BUFF_SIZE: + obs = (int)num; + p = ctx->obuf; + if ((obs > DEFAULT_LINEBUFFER_SIZE) && (obs != ctx->obuf_size)) { + p = OPENSSL_malloc((int)num); + if (p == NULL) + goto malloc_error; + } + if (ctx->obuf != p) { + if (ctx->obuf_len > obs) { + ctx->obuf_len = obs; + } + memcpy(p, ctx->obuf, ctx->obuf_len); + OPENSSL_free(ctx->obuf); + ctx->obuf = p; + ctx->obuf_size = obs; + } + break; + case BIO_C_DO_STATE_MACHINE: + if (b->next_bio == NULL) + return 0; + BIO_clear_retry_flags(b); + ret = BIO_ctrl(b->next_bio, cmd, num, ptr); + BIO_copy_next_retry(b); + break; + + case BIO_CTRL_FLUSH: + if (b->next_bio == NULL) + return 0; + if (ctx->obuf_len <= 0) { + ret = BIO_ctrl(b->next_bio, cmd, num, ptr); + break; + } + + for (;;) { + BIO_clear_retry_flags(b); + if (ctx->obuf_len > 0) { + r = BIO_write(b->next_bio, ctx->obuf, ctx->obuf_len); + BIO_copy_next_retry(b); + if (r <= 0) + return (long)r; + if (r < ctx->obuf_len) + memmove(ctx->obuf, ctx->obuf + r, ctx->obuf_len - r); + ctx->obuf_len -= r; + } else { + ctx->obuf_len = 0; + break; + } + } + ret = BIO_ctrl(b->next_bio, cmd, num, ptr); + break; + case BIO_CTRL_DUP: + dbio = (BIO *)ptr; + if (!BIO_set_write_buffer_size(dbio, ctx->obuf_size)) + ret = 0; + break; + default: + if (b->next_bio == NULL) + return 0; + ret = BIO_ctrl(b->next_bio, cmd, num, ptr); + break; + } + return ret; + malloc_error: + BIOerr(BIO_F_LINEBUFFER_CTRL, ERR_R_MALLOC_FAILURE); + return 0; +} + +static long linebuffer_callback_ctrl(BIO *b, int cmd, BIO_info_cb *fp) +{ + long ret = 1; + + if (b->next_bio == NULL) + return 0; + switch (cmd) { + default: + ret = BIO_callback_ctrl(b->next_bio, cmd, fp); + break; + } + return ret; +} + +static int linebuffer_gets(BIO *b, char *buf, int size) +{ + if (b->next_bio == NULL) + return 0; + return BIO_gets(b->next_bio, buf, size); +} + +static int linebuffer_puts(BIO *b, const char *str) +{ + return linebuffer_write(b, str, strlen(str)); +} diff --git a/roms/edk2/CryptoPkg/Library/OpensslLib/openssl/crypto/bio/bf_nbio.c b/roms/edk2/CryptoPkg/Library/OpensslLib/openssl/crypto/bio/bf_nbio.c new file mode 100644 index 000000000..dd7011ab6 --- /dev/null +++ b/roms/edk2/CryptoPkg/Library/OpensslLib/openssl/crypto/bio/bf_nbio.c @@ -0,0 +1,200 @@ +/* + * Copyright 1995-2018 The OpenSSL Project Authors. All Rights Reserved. + * + * Licensed under the OpenSSL license (the "License"). You may not use + * this file except in compliance with the License. You can obtain a copy + * in the file LICENSE in the source distribution or at + * https://www.openssl.org/source/license.html + */ + +#include <stdio.h> +#include <errno.h> +#include "bio_local.h" +#include "internal/cryptlib.h" +#include <openssl/rand.h> + +/* + * BIO_put and BIO_get both add to the digest, BIO_gets returns the digest + */ + +static int nbiof_write(BIO *h, const char *buf, int num); +static int nbiof_read(BIO *h, char *buf, int size); +static int nbiof_puts(BIO *h, const char *str); +static int nbiof_gets(BIO *h, char *str, int size); +static long nbiof_ctrl(BIO *h, int cmd, long arg1, void *arg2); +static int nbiof_new(BIO *h); +static int nbiof_free(BIO *data); +static long nbiof_callback_ctrl(BIO *h, int cmd, BIO_info_cb *fp); +typedef struct nbio_test_st { + /* only set if we sent a 'should retry' error */ + int lrn; + int lwn; +} NBIO_TEST; + +static const BIO_METHOD methods_nbiof = { + BIO_TYPE_NBIO_TEST, + "non-blocking IO test filter", + /* TODO: Convert to new style write function */ + bwrite_conv, + nbiof_write, + /* TODO: Convert to new style read function */ + bread_conv, + nbiof_read, + nbiof_puts, + nbiof_gets, + nbiof_ctrl, + nbiof_new, + nbiof_free, + nbiof_callback_ctrl, +}; + +const BIO_METHOD *BIO_f_nbio_test(void) +{ + return &methods_nbiof; +} + +static int nbiof_new(BIO *bi) +{ + NBIO_TEST *nt; + + if ((nt = OPENSSL_zalloc(sizeof(*nt))) == NULL) { + BIOerr(BIO_F_NBIOF_NEW, ERR_R_MALLOC_FAILURE); + return 0; + } + nt->lrn = -1; + nt->lwn = -1; + bi->ptr = (char *)nt; + bi->init = 1; + return 1; +} + +static int nbiof_free(BIO *a) +{ + if (a == NULL) + return 0; + OPENSSL_free(a->ptr); + a->ptr = NULL; + a->init = 0; + a->flags = 0; + return 1; +} + +static int nbiof_read(BIO *b, char *out, int outl) +{ + int ret = 0; + int num; + unsigned char n; + + if (out == NULL) + return 0; + if (b->next_bio == NULL) + return 0; + + BIO_clear_retry_flags(b); + if (RAND_priv_bytes(&n, 1) <= 0) + return -1; + num = (n & 0x07); + + if (outl > num) + outl = num; + + if (num == 0) { + ret = -1; + BIO_set_retry_read(b); + } else { + ret = BIO_read(b->next_bio, out, outl); + if (ret < 0) + BIO_copy_next_retry(b); + } + return ret; +} + +static int nbiof_write(BIO *b, const char *in, int inl) +{ + NBIO_TEST *nt; + int ret = 0; + int num; + unsigned char n; + + if ((in == NULL) || (inl <= 0)) + return 0; + if (b->next_bio == NULL) + return 0; + nt = (NBIO_TEST *)b->ptr; + + BIO_clear_retry_flags(b); + + if (nt->lwn > 0) { + num = nt->lwn; + nt->lwn = 0; + } else { + if (RAND_priv_bytes(&n, 1) <= 0) + return -1; + num = (n & 7); + } + + if (inl > num) + inl = num; + + if (num == 0) { + ret = -1; + BIO_set_retry_write(b); + } else { + ret = BIO_write(b->next_bio, in, inl); + if (ret < 0) { + BIO_copy_next_retry(b); + nt->lwn = inl; + } + } + return ret; +} + +static long nbiof_ctrl(BIO *b, int cmd, long num, void *ptr) +{ + long ret; + + if (b->next_bio == NULL) + return 0; + switch (cmd) { + case BIO_C_DO_STATE_MACHINE: + BIO_clear_retry_flags(b); + ret = BIO_ctrl(b->next_bio, cmd, num, ptr); + BIO_copy_next_retry(b); + break; + case BIO_CTRL_DUP: + ret = 0L; + break; + default: + ret = BIO_ctrl(b->next_bio, cmd, num, ptr); + break; + } + return ret; +} + +static long nbiof_callback_ctrl(BIO *b, int cmd, BIO_info_cb *fp) +{ + long ret = 1; + + if (b->next_bio == NULL) + return 0; + switch (cmd) { + default: + ret = BIO_callback_ctrl(b->next_bio, cmd, fp); + break; + } + return ret; +} + +static int nbiof_gets(BIO *bp, char *buf, int size) +{ + if (bp->next_bio == NULL) + return 0; + return BIO_gets(bp->next_bio, buf, size); +} + +static int nbiof_puts(BIO *bp, const char *str) +{ + if (bp->next_bio == NULL) + return 0; + return BIO_puts(bp->next_bio, str); +} diff --git a/roms/edk2/CryptoPkg/Library/OpensslLib/openssl/crypto/bio/bf_null.c b/roms/edk2/CryptoPkg/Library/OpensslLib/openssl/crypto/bio/bf_null.c new file mode 100644 index 000000000..48c6be692 --- /dev/null +++ b/roms/edk2/CryptoPkg/Library/OpensslLib/openssl/crypto/bio/bf_null.c @@ -0,0 +1,122 @@ +/* + * Copyright 1995-2018 The OpenSSL Project Authors. All Rights Reserved. + * + * Licensed under the OpenSSL license (the "License"). You may not use + * this file except in compliance with the License. You can obtain a copy + * in the file LICENSE in the source distribution or at + * https://www.openssl.org/source/license.html + */ + +#include <stdio.h> +#include <errno.h> +#include "bio_local.h" +#include "internal/cryptlib.h" + +/* + * BIO_put and BIO_get both add to the digest, BIO_gets returns the digest + */ + +static int nullf_write(BIO *h, const char *buf, int num); +static int nullf_read(BIO *h, char *buf, int size); +static int nullf_puts(BIO *h, const char *str); +static int nullf_gets(BIO *h, char *str, int size); +static long nullf_ctrl(BIO *h, int cmd, long arg1, void *arg2); +static long nullf_callback_ctrl(BIO *h, int cmd, BIO_info_cb *fp); +static const BIO_METHOD methods_nullf = { + BIO_TYPE_NULL_FILTER, + "NULL filter", + /* TODO: Convert to new style write function */ + bwrite_conv, + nullf_write, + /* TODO: Convert to new style read function */ + bread_conv, + nullf_read, + nullf_puts, + nullf_gets, + nullf_ctrl, + NULL, + NULL, + nullf_callback_ctrl, +}; + +const BIO_METHOD *BIO_f_null(void) +{ + return &methods_nullf; +} + +static int nullf_read(BIO *b, char *out, int outl) +{ + int ret = 0; + + if (out == NULL) + return 0; + if (b->next_bio == NULL) + return 0; + ret = BIO_read(b->next_bio, out, outl); + BIO_clear_retry_flags(b); + BIO_copy_next_retry(b); + return ret; +} + +static int nullf_write(BIO *b, const char *in, int inl) +{ + int ret = 0; + + if ((in == NULL) || (inl <= 0)) + return 0; + if (b->next_bio == NULL) + return 0; + ret = BIO_write(b->next_bio, in, inl); + BIO_clear_retry_flags(b); + BIO_copy_next_retry(b); + return ret; +} + +static long nullf_ctrl(BIO *b, int cmd, long num, void *ptr) +{ + long ret; + + if (b->next_bio == NULL) + return 0; + switch (cmd) { + case BIO_C_DO_STATE_MACHINE: + BIO_clear_retry_flags(b); + ret = BIO_ctrl(b->next_bio, cmd, num, ptr); + BIO_copy_next_retry(b); + break; + case BIO_CTRL_DUP: + ret = 0L; + break; + default: + ret = BIO_ctrl(b->next_bio, cmd, num, ptr); + } + return ret; +} + +static long nullf_callback_ctrl(BIO *b, int cmd, BIO_info_cb *fp) +{ + long ret = 1; + + if (b->next_bio == NULL) + return 0; + switch (cmd) { + default: + ret = BIO_callback_ctrl(b->next_bio, cmd, fp); + break; + } + return ret; +} + +static int nullf_gets(BIO *bp, char *buf, int size) +{ + if (bp->next_bio == NULL) + return 0; + return BIO_gets(bp->next_bio, buf, size); +} + +static int nullf_puts(BIO *bp, const char *str) +{ + if (bp->next_bio == NULL) + return 0; + return BIO_puts(bp->next_bio, str); +} diff --git a/roms/edk2/CryptoPkg/Library/OpensslLib/openssl/crypto/bio/bio_cb.c b/roms/edk2/CryptoPkg/Library/OpensslLib/openssl/crypto/bio/bio_cb.c new file mode 100644 index 000000000..a153100a8 --- /dev/null +++ b/roms/edk2/CryptoPkg/Library/OpensslLib/openssl/crypto/bio/bio_cb.c @@ -0,0 +1,98 @@ +/* + * Copyright 1995-2017 The OpenSSL Project Authors. All Rights Reserved. + * + * Licensed under the OpenSSL license (the "License"). You may not use + * this file except in compliance with the License. You can obtain a copy + * in the file LICENSE in the source distribution or at + * https://www.openssl.org/source/license.html + */ + +#include <stdio.h> +#include <string.h> +#include <stdlib.h> +#include "bio_local.h" +#include "internal/cryptlib.h" +#include <openssl/err.h> + +long BIO_debug_callback(BIO *bio, int cmd, const char *argp, + int argi, long argl, long ret) +{ + BIO *b; + char buf[256]; + char *p; + long r = 1; + int len, left; + + if (BIO_CB_RETURN & cmd) + r = ret; + + len = BIO_snprintf(buf, sizeof(buf), "BIO[%p]: ", (void *)bio); + + /* Ignore errors and continue printing the other information. */ + if (len < 0) + len = 0; + p = buf + len; + left = sizeof(buf) - len; + + switch (cmd) { + case BIO_CB_FREE: + BIO_snprintf(p, left, "Free - %s\n", bio->method->name); + break; + case BIO_CB_READ: + if (bio->method->type & BIO_TYPE_DESCRIPTOR) + BIO_snprintf(p, left, "read(%d,%lu) - %s fd=%d\n", + bio->num, (unsigned long)argi, + bio->method->name, bio->num); + else + BIO_snprintf(p, left, "read(%d,%lu) - %s\n", + bio->num, (unsigned long)argi, bio->method->name); + break; + case BIO_CB_WRITE: + if (bio->method->type & BIO_TYPE_DESCRIPTOR) + BIO_snprintf(p, left, "write(%d,%lu) - %s fd=%d\n", + bio->num, (unsigned long)argi, + bio->method->name, bio->num); + else + BIO_snprintf(p, left, "write(%d,%lu) - %s\n", + bio->num, (unsigned long)argi, bio->method->name); + break; + case BIO_CB_PUTS: + BIO_snprintf(p, left, "puts() - %s\n", bio->method->name); + break; + case BIO_CB_GETS: + BIO_snprintf(p, left, "gets(%lu) - %s\n", (unsigned long)argi, + bio->method->name); + break; + case BIO_CB_CTRL: + BIO_snprintf(p, left, "ctrl(%lu) - %s\n", (unsigned long)argi, + bio->method->name); + break; + case BIO_CB_RETURN | BIO_CB_READ: + BIO_snprintf(p, left, "read return %ld\n", ret); + break; + case BIO_CB_RETURN | BIO_CB_WRITE: + BIO_snprintf(p, left, "write return %ld\n", ret); + break; + case BIO_CB_RETURN | BIO_CB_GETS: + BIO_snprintf(p, left, "gets return %ld\n", ret); + break; + case BIO_CB_RETURN | BIO_CB_PUTS: + BIO_snprintf(p, left, "puts return %ld\n", ret); + break; + case BIO_CB_RETURN | BIO_CB_CTRL: + BIO_snprintf(p, left, "ctrl return %ld\n", ret); + break; + default: + BIO_snprintf(p, left, "bio callback - unknown type (%d)\n", cmd); + break; + } + + b = (BIO *)bio->cb_arg; + if (b != NULL) + BIO_write(b, buf, strlen(buf)); +#if !defined(OPENSSL_NO_STDIO) + else + fputs(buf, stderr); +#endif + return r; +} diff --git a/roms/edk2/CryptoPkg/Library/OpensslLib/openssl/crypto/bio/bio_err.c b/roms/edk2/CryptoPkg/Library/OpensslLib/openssl/crypto/bio/bio_err.c new file mode 100644 index 000000000..7aa9dabb2 --- /dev/null +++ b/roms/edk2/CryptoPkg/Library/OpensslLib/openssl/crypto/bio/bio_err.c @@ -0,0 +1,145 @@ +/* + * Generated by util/mkerr.pl DO NOT EDIT + * Copyright 1995-2018 The OpenSSL Project Authors. All Rights Reserved. + * + * Licensed under the OpenSSL license (the "License"). You may not use + * this file except in compliance with the License. You can obtain a copy + * in the file LICENSE in the source distribution or at + * https://www.openssl.org/source/license.html + */ + +#include <openssl/err.h> +#include <openssl/bioerr.h> + +#ifndef OPENSSL_NO_ERR + +static const ERR_STRING_DATA BIO_str_functs[] = { + {ERR_PACK(ERR_LIB_BIO, BIO_F_ACPT_STATE, 0), "acpt_state"}, + {ERR_PACK(ERR_LIB_BIO, BIO_F_ADDRINFO_WRAP, 0), "addrinfo_wrap"}, + {ERR_PACK(ERR_LIB_BIO, BIO_F_ADDR_STRINGS, 0), "addr_strings"}, + {ERR_PACK(ERR_LIB_BIO, BIO_F_BIO_ACCEPT, 0), "BIO_accept"}, + {ERR_PACK(ERR_LIB_BIO, BIO_F_BIO_ACCEPT_EX, 0), "BIO_accept_ex"}, + {ERR_PACK(ERR_LIB_BIO, BIO_F_BIO_ACCEPT_NEW, 0), "BIO_ACCEPT_new"}, + {ERR_PACK(ERR_LIB_BIO, BIO_F_BIO_ADDR_NEW, 0), "BIO_ADDR_new"}, + {ERR_PACK(ERR_LIB_BIO, BIO_F_BIO_BIND, 0), "BIO_bind"}, + {ERR_PACK(ERR_LIB_BIO, BIO_F_BIO_CALLBACK_CTRL, 0), "BIO_callback_ctrl"}, + {ERR_PACK(ERR_LIB_BIO, BIO_F_BIO_CONNECT, 0), "BIO_connect"}, + {ERR_PACK(ERR_LIB_BIO, BIO_F_BIO_CONNECT_NEW, 0), "BIO_CONNECT_new"}, + {ERR_PACK(ERR_LIB_BIO, BIO_F_BIO_CTRL, 0), "BIO_ctrl"}, + {ERR_PACK(ERR_LIB_BIO, BIO_F_BIO_GETS, 0), "BIO_gets"}, + {ERR_PACK(ERR_LIB_BIO, BIO_F_BIO_GET_HOST_IP, 0), "BIO_get_host_ip"}, + {ERR_PACK(ERR_LIB_BIO, BIO_F_BIO_GET_NEW_INDEX, 0), "BIO_get_new_index"}, + {ERR_PACK(ERR_LIB_BIO, BIO_F_BIO_GET_PORT, 0), "BIO_get_port"}, + {ERR_PACK(ERR_LIB_BIO, BIO_F_BIO_LISTEN, 0), "BIO_listen"}, + {ERR_PACK(ERR_LIB_BIO, BIO_F_BIO_LOOKUP, 0), "BIO_lookup"}, + {ERR_PACK(ERR_LIB_BIO, BIO_F_BIO_LOOKUP_EX, 0), "BIO_lookup_ex"}, + {ERR_PACK(ERR_LIB_BIO, BIO_F_BIO_MAKE_PAIR, 0), "bio_make_pair"}, + {ERR_PACK(ERR_LIB_BIO, BIO_F_BIO_METH_NEW, 0), "BIO_meth_new"}, + {ERR_PACK(ERR_LIB_BIO, BIO_F_BIO_NEW, 0), "BIO_new"}, + {ERR_PACK(ERR_LIB_BIO, BIO_F_BIO_NEW_DGRAM_SCTP, 0), "BIO_new_dgram_sctp"}, + {ERR_PACK(ERR_LIB_BIO, BIO_F_BIO_NEW_FILE, 0), "BIO_new_file"}, + {ERR_PACK(ERR_LIB_BIO, BIO_F_BIO_NEW_MEM_BUF, 0), "BIO_new_mem_buf"}, + {ERR_PACK(ERR_LIB_BIO, BIO_F_BIO_NREAD, 0), "BIO_nread"}, + {ERR_PACK(ERR_LIB_BIO, BIO_F_BIO_NREAD0, 0), "BIO_nread0"}, + {ERR_PACK(ERR_LIB_BIO, BIO_F_BIO_NWRITE, 0), "BIO_nwrite"}, + {ERR_PACK(ERR_LIB_BIO, BIO_F_BIO_NWRITE0, 0), "BIO_nwrite0"}, + {ERR_PACK(ERR_LIB_BIO, BIO_F_BIO_PARSE_HOSTSERV, 0), "BIO_parse_hostserv"}, + {ERR_PACK(ERR_LIB_BIO, BIO_F_BIO_PUTS, 0), "BIO_puts"}, + {ERR_PACK(ERR_LIB_BIO, BIO_F_BIO_READ, 0), "BIO_read"}, + {ERR_PACK(ERR_LIB_BIO, BIO_F_BIO_READ_EX, 0), "BIO_read_ex"}, + {ERR_PACK(ERR_LIB_BIO, BIO_F_BIO_READ_INTERN, 0), "bio_read_intern"}, + {ERR_PACK(ERR_LIB_BIO, BIO_F_BIO_SOCKET, 0), "BIO_socket"}, + {ERR_PACK(ERR_LIB_BIO, BIO_F_BIO_SOCKET_NBIO, 0), "BIO_socket_nbio"}, + {ERR_PACK(ERR_LIB_BIO, BIO_F_BIO_SOCK_INFO, 0), "BIO_sock_info"}, + {ERR_PACK(ERR_LIB_BIO, BIO_F_BIO_SOCK_INIT, 0), "BIO_sock_init"}, + {ERR_PACK(ERR_LIB_BIO, BIO_F_BIO_WRITE, 0), "BIO_write"}, + {ERR_PACK(ERR_LIB_BIO, BIO_F_BIO_WRITE_EX, 0), "BIO_write_ex"}, + {ERR_PACK(ERR_LIB_BIO, BIO_F_BIO_WRITE_INTERN, 0), "bio_write_intern"}, + {ERR_PACK(ERR_LIB_BIO, BIO_F_BUFFER_CTRL, 0), "buffer_ctrl"}, + {ERR_PACK(ERR_LIB_BIO, BIO_F_CONN_CTRL, 0), "conn_ctrl"}, + {ERR_PACK(ERR_LIB_BIO, BIO_F_CONN_STATE, 0), "conn_state"}, + {ERR_PACK(ERR_LIB_BIO, BIO_F_DGRAM_SCTP_NEW, 0), "dgram_sctp_new"}, + {ERR_PACK(ERR_LIB_BIO, BIO_F_DGRAM_SCTP_READ, 0), "dgram_sctp_read"}, + {ERR_PACK(ERR_LIB_BIO, BIO_F_DGRAM_SCTP_WRITE, 0), "dgram_sctp_write"}, + {ERR_PACK(ERR_LIB_BIO, BIO_F_DOAPR_OUTCH, 0), "doapr_outch"}, + {ERR_PACK(ERR_LIB_BIO, BIO_F_FILE_CTRL, 0), "file_ctrl"}, + {ERR_PACK(ERR_LIB_BIO, BIO_F_FILE_READ, 0), "file_read"}, + {ERR_PACK(ERR_LIB_BIO, BIO_F_LINEBUFFER_CTRL, 0), "linebuffer_ctrl"}, + {ERR_PACK(ERR_LIB_BIO, BIO_F_LINEBUFFER_NEW, 0), "linebuffer_new"}, + {ERR_PACK(ERR_LIB_BIO, BIO_F_MEM_WRITE, 0), "mem_write"}, + {ERR_PACK(ERR_LIB_BIO, BIO_F_NBIOF_NEW, 0), "nbiof_new"}, + {ERR_PACK(ERR_LIB_BIO, BIO_F_SLG_WRITE, 0), "slg_write"}, + {ERR_PACK(ERR_LIB_BIO, BIO_F_SSL_NEW, 0), "SSL_new"}, + {0, NULL} +}; + +static const ERR_STRING_DATA BIO_str_reasons[] = { + {ERR_PACK(ERR_LIB_BIO, 0, BIO_R_ACCEPT_ERROR), "accept error"}, + {ERR_PACK(ERR_LIB_BIO, 0, BIO_R_ADDRINFO_ADDR_IS_NOT_AF_INET), + "addrinfo addr is not af inet"}, + {ERR_PACK(ERR_LIB_BIO, 0, BIO_R_AMBIGUOUS_HOST_OR_SERVICE), + "ambiguous host or service"}, + {ERR_PACK(ERR_LIB_BIO, 0, BIO_R_BAD_FOPEN_MODE), "bad fopen mode"}, + {ERR_PACK(ERR_LIB_BIO, 0, BIO_R_BROKEN_PIPE), "broken pipe"}, + {ERR_PACK(ERR_LIB_BIO, 0, BIO_R_CONNECT_ERROR), "connect error"}, + {ERR_PACK(ERR_LIB_BIO, 0, BIO_R_GETHOSTBYNAME_ADDR_IS_NOT_AF_INET), + "gethostbyname addr is not af inet"}, + {ERR_PACK(ERR_LIB_BIO, 0, BIO_R_GETSOCKNAME_ERROR), "getsockname error"}, + {ERR_PACK(ERR_LIB_BIO, 0, BIO_R_GETSOCKNAME_TRUNCATED_ADDRESS), + "getsockname truncated address"}, + {ERR_PACK(ERR_LIB_BIO, 0, BIO_R_GETTING_SOCKTYPE), "getting socktype"}, + {ERR_PACK(ERR_LIB_BIO, 0, BIO_R_INVALID_ARGUMENT), "invalid argument"}, + {ERR_PACK(ERR_LIB_BIO, 0, BIO_R_INVALID_SOCKET), "invalid socket"}, + {ERR_PACK(ERR_LIB_BIO, 0, BIO_R_IN_USE), "in use"}, + {ERR_PACK(ERR_LIB_BIO, 0, BIO_R_LENGTH_TOO_LONG), "length too long"}, + {ERR_PACK(ERR_LIB_BIO, 0, BIO_R_LISTEN_V6_ONLY), "listen v6 only"}, + {ERR_PACK(ERR_LIB_BIO, 0, BIO_R_LOOKUP_RETURNED_NOTHING), + "lookup returned nothing"}, + {ERR_PACK(ERR_LIB_BIO, 0, BIO_R_MALFORMED_HOST_OR_SERVICE), + "malformed host or service"}, + {ERR_PACK(ERR_LIB_BIO, 0, BIO_R_NBIO_CONNECT_ERROR), "nbio connect error"}, + {ERR_PACK(ERR_LIB_BIO, 0, BIO_R_NO_ACCEPT_ADDR_OR_SERVICE_SPECIFIED), + "no accept addr or service specified"}, + {ERR_PACK(ERR_LIB_BIO, 0, BIO_R_NO_HOSTNAME_OR_SERVICE_SPECIFIED), + "no hostname or service specified"}, + {ERR_PACK(ERR_LIB_BIO, 0, BIO_R_NO_PORT_DEFINED), "no port defined"}, + {ERR_PACK(ERR_LIB_BIO, 0, BIO_R_NO_SUCH_FILE), "no such file"}, + {ERR_PACK(ERR_LIB_BIO, 0, BIO_R_NULL_PARAMETER), "null parameter"}, + {ERR_PACK(ERR_LIB_BIO, 0, BIO_R_UNABLE_TO_BIND_SOCKET), + "unable to bind socket"}, + {ERR_PACK(ERR_LIB_BIO, 0, BIO_R_UNABLE_TO_CREATE_SOCKET), + "unable to create socket"}, + {ERR_PACK(ERR_LIB_BIO, 0, BIO_R_UNABLE_TO_KEEPALIVE), + "unable to keepalive"}, + {ERR_PACK(ERR_LIB_BIO, 0, BIO_R_UNABLE_TO_LISTEN_SOCKET), + "unable to listen socket"}, + {ERR_PACK(ERR_LIB_BIO, 0, BIO_R_UNABLE_TO_NODELAY), "unable to nodelay"}, + {ERR_PACK(ERR_LIB_BIO, 0, BIO_R_UNABLE_TO_REUSEADDR), + "unable to reuseaddr"}, + {ERR_PACK(ERR_LIB_BIO, 0, BIO_R_UNAVAILABLE_IP_FAMILY), + "unavailable ip family"}, + {ERR_PACK(ERR_LIB_BIO, 0, BIO_R_UNINITIALIZED), "uninitialized"}, + {ERR_PACK(ERR_LIB_BIO, 0, BIO_R_UNKNOWN_INFO_TYPE), "unknown info type"}, + {ERR_PACK(ERR_LIB_BIO, 0, BIO_R_UNSUPPORTED_IP_FAMILY), + "unsupported ip family"}, + {ERR_PACK(ERR_LIB_BIO, 0, BIO_R_UNSUPPORTED_METHOD), "unsupported method"}, + {ERR_PACK(ERR_LIB_BIO, 0, BIO_R_UNSUPPORTED_PROTOCOL_FAMILY), + "unsupported protocol family"}, + {ERR_PACK(ERR_LIB_BIO, 0, BIO_R_WRITE_TO_READ_ONLY_BIO), + "write to read only BIO"}, + {ERR_PACK(ERR_LIB_BIO, 0, BIO_R_WSASTARTUP), "WSAStartup"}, + {0, NULL} +}; + +#endif + +int ERR_load_BIO_strings(void) +{ +#ifndef OPENSSL_NO_ERR + if (ERR_func_error_string(BIO_str_functs[0].error) == NULL) { + ERR_load_strings_const(BIO_str_functs); + ERR_load_strings_const(BIO_str_reasons); + } +#endif + return 1; +} diff --git a/roms/edk2/CryptoPkg/Library/OpensslLib/openssl/crypto/bio/bio_lib.c b/roms/edk2/CryptoPkg/Library/OpensslLib/openssl/crypto/bio/bio_lib.c new file mode 100644 index 000000000..d2202e537 --- /dev/null +++ b/roms/edk2/CryptoPkg/Library/OpensslLib/openssl/crypto/bio/bio_lib.c @@ -0,0 +1,786 @@ +/* + * Copyright 1995-2018 The OpenSSL Project Authors. All Rights Reserved. + * + * Licensed under the OpenSSL license (the "License"). You may not use + * this file except in compliance with the License. You can obtain a copy + * in the file LICENSE in the source distribution or at + * https://www.openssl.org/source/license.html + */ + +#include <stdio.h> +#include <errno.h> +#include <openssl/crypto.h> +#include "bio_local.h" +#include "internal/cryptlib.h" + + +/* + * Helper macro for the callback to determine whether an operator expects a + * len parameter or not + */ +#define HAS_LEN_OPER(o) ((o) == BIO_CB_READ || (o) == BIO_CB_WRITE || \ + (o) == BIO_CB_GETS) + +/* + * Helper function to work out whether to call the new style callback or the old + * one, and translate between the two. + * + * This has a long return type for consistency with the old callback. Similarly + * for the "long" used for "inret" + */ +static long bio_call_callback(BIO *b, int oper, const char *argp, size_t len, + int argi, long argl, long inret, size_t *processed) +{ + long ret; + int bareoper; + + if (b->callback_ex != NULL) + return b->callback_ex(b, oper, argp, len, argi, argl, inret, processed); + + /* Strip off any BIO_CB_RETURN flag */ + bareoper = oper & ~BIO_CB_RETURN; + + /* + * We have an old style callback, so we will have to do nasty casts and + * check for overflows. + */ + if (HAS_LEN_OPER(bareoper)) { + /* In this case |len| is set, and should be used instead of |argi| */ + if (len > INT_MAX) + return -1; + + argi = (int)len; + } + + if (inret > 0 && (oper & BIO_CB_RETURN) && bareoper != BIO_CB_CTRL) { + if (*processed > INT_MAX) + return -1; + inret = *processed; + } + + ret = b->callback(b, oper, argp, argi, argl, inret); + + if (ret > 0 && (oper & BIO_CB_RETURN) && bareoper != BIO_CB_CTRL) { + *processed = (size_t)ret; + ret = 1; + } + + return ret; +} + +BIO *BIO_new(const BIO_METHOD *method) +{ + BIO *bio = OPENSSL_zalloc(sizeof(*bio)); + + if (bio == NULL) { + BIOerr(BIO_F_BIO_NEW, ERR_R_MALLOC_FAILURE); + return NULL; + } + + bio->method = method; + bio->shutdown = 1; + bio->references = 1; + + if (!CRYPTO_new_ex_data(CRYPTO_EX_INDEX_BIO, bio, &bio->ex_data)) + goto err; + + bio->lock = CRYPTO_THREAD_lock_new(); + if (bio->lock == NULL) { + BIOerr(BIO_F_BIO_NEW, ERR_R_MALLOC_FAILURE); + CRYPTO_free_ex_data(CRYPTO_EX_INDEX_BIO, bio, &bio->ex_data); + goto err; + } + + if (method->create != NULL && !method->create(bio)) { + BIOerr(BIO_F_BIO_NEW, ERR_R_INIT_FAIL); + CRYPTO_free_ex_data(CRYPTO_EX_INDEX_BIO, bio, &bio->ex_data); + CRYPTO_THREAD_lock_free(bio->lock); + goto err; + } + if (method->create == NULL) + bio->init = 1; + + return bio; + +err: + OPENSSL_free(bio); + return NULL; +} + +int BIO_free(BIO *a) +{ + int ret; + + if (a == NULL) + return 0; + + if (CRYPTO_DOWN_REF(&a->references, &ret, a->lock) <= 0) + return 0; + + REF_PRINT_COUNT("BIO", a); + if (ret > 0) + return 1; + REF_ASSERT_ISNT(ret < 0); + + if (a->callback != NULL || a->callback_ex != NULL) { + ret = (int)bio_call_callback(a, BIO_CB_FREE, NULL, 0, 0, 0L, 1L, NULL); + if (ret <= 0) + return ret; + } + + if ((a->method != NULL) && (a->method->destroy != NULL)) + a->method->destroy(a); + + CRYPTO_free_ex_data(CRYPTO_EX_INDEX_BIO, a, &a->ex_data); + + CRYPTO_THREAD_lock_free(a->lock); + + OPENSSL_free(a); + + return 1; +} + +void BIO_set_data(BIO *a, void *ptr) +{ + a->ptr = ptr; +} + +void *BIO_get_data(BIO *a) +{ + return a->ptr; +} + +void BIO_set_init(BIO *a, int init) +{ + a->init = init; +} + +int BIO_get_init(BIO *a) +{ + return a->init; +} + +void BIO_set_shutdown(BIO *a, int shut) +{ + a->shutdown = shut; +} + +int BIO_get_shutdown(BIO *a) +{ + return a->shutdown; +} + +void BIO_vfree(BIO *a) +{ + BIO_free(a); +} + +int BIO_up_ref(BIO *a) +{ + int i; + + if (CRYPTO_UP_REF(&a->references, &i, a->lock) <= 0) + return 0; + + REF_PRINT_COUNT("BIO", a); + REF_ASSERT_ISNT(i < 2); + return ((i > 1) ? 1 : 0); +} + +void BIO_clear_flags(BIO *b, int flags) +{ + b->flags &= ~flags; +} + +int BIO_test_flags(const BIO *b, int flags) +{ + return (b->flags & flags); +} + +void BIO_set_flags(BIO *b, int flags) +{ + b->flags |= flags; +} + +BIO_callback_fn BIO_get_callback(const BIO *b) +{ + return b->callback; +} + +void BIO_set_callback(BIO *b, BIO_callback_fn cb) +{ + b->callback = cb; +} + +BIO_callback_fn_ex BIO_get_callback_ex(const BIO *b) +{ + return b->callback_ex; +} + +void BIO_set_callback_ex(BIO *b, BIO_callback_fn_ex cb) +{ + b->callback_ex = cb; +} + +void BIO_set_callback_arg(BIO *b, char *arg) +{ + b->cb_arg = arg; +} + +char *BIO_get_callback_arg(const BIO *b) +{ + return b->cb_arg; +} + +const char *BIO_method_name(const BIO *b) +{ + return b->method->name; +} + +int BIO_method_type(const BIO *b) +{ + return b->method->type; +} + +/* + * This is essentially the same as BIO_read_ex() except that it allows + * 0 or a negative value to indicate failure (retryable or not) in the return. + * This is for compatibility with the old style BIO_read(), where existing code + * may make assumptions about the return value that it might get. + */ +static int bio_read_intern(BIO *b, void *data, size_t dlen, size_t *readbytes) +{ + int ret; + + if ((b == NULL) || (b->method == NULL) || (b->method->bread == NULL)) { + BIOerr(BIO_F_BIO_READ_INTERN, BIO_R_UNSUPPORTED_METHOD); + return -2; + } + + if ((b->callback != NULL || b->callback_ex != NULL) && + ((ret = (int)bio_call_callback(b, BIO_CB_READ, data, dlen, 0, 0L, 1L, + NULL)) <= 0)) + return ret; + + if (!b->init) { + BIOerr(BIO_F_BIO_READ_INTERN, BIO_R_UNINITIALIZED); + return -2; + } + + ret = b->method->bread(b, data, dlen, readbytes); + + if (ret > 0) + b->num_read += (uint64_t)*readbytes; + + if (b->callback != NULL || b->callback_ex != NULL) + ret = (int)bio_call_callback(b, BIO_CB_READ | BIO_CB_RETURN, data, + dlen, 0, 0L, ret, readbytes); + + /* Shouldn't happen */ + if (ret > 0 && *readbytes > dlen) { + BIOerr(BIO_F_BIO_READ_INTERN, ERR_R_INTERNAL_ERROR); + return -1; + } + + return ret; +} + +int BIO_read(BIO *b, void *data, int dlen) +{ + size_t readbytes; + int ret; + + if (dlen < 0) + return 0; + + ret = bio_read_intern(b, data, (size_t)dlen, &readbytes); + + if (ret > 0) { + /* *readbytes should always be <= dlen */ + ret = (int)readbytes; + } + + return ret; +} + +int BIO_read_ex(BIO *b, void *data, size_t dlen, size_t *readbytes) +{ + int ret; + + ret = bio_read_intern(b, data, dlen, readbytes); + + if (ret > 0) + ret = 1; + else + ret = 0; + + return ret; +} + +static int bio_write_intern(BIO *b, const void *data, size_t dlen, + size_t *written) +{ + int ret; + + if (b == NULL) + return 0; + + if ((b->method == NULL) || (b->method->bwrite == NULL)) { + BIOerr(BIO_F_BIO_WRITE_INTERN, BIO_R_UNSUPPORTED_METHOD); + return -2; + } + + if ((b->callback != NULL || b->callback_ex != NULL) && + ((ret = (int)bio_call_callback(b, BIO_CB_WRITE, data, dlen, 0, 0L, 1L, + NULL)) <= 0)) + return ret; + + if (!b->init) { + BIOerr(BIO_F_BIO_WRITE_INTERN, BIO_R_UNINITIALIZED); + return -2; + } + + ret = b->method->bwrite(b, data, dlen, written); + + if (ret > 0) + b->num_write += (uint64_t)*written; + + if (b->callback != NULL || b->callback_ex != NULL) + ret = (int)bio_call_callback(b, BIO_CB_WRITE | BIO_CB_RETURN, data, + dlen, 0, 0L, ret, written); + + return ret; +} + +int BIO_write(BIO *b, const void *data, int dlen) +{ + size_t written; + int ret; + + if (dlen < 0) + return 0; + + ret = bio_write_intern(b, data, (size_t)dlen, &written); + + if (ret > 0) { + /* *written should always be <= dlen */ + ret = (int)written; + } + + return ret; +} + +int BIO_write_ex(BIO *b, const void *data, size_t dlen, size_t *written) +{ + int ret; + + ret = bio_write_intern(b, data, dlen, written); + + if (ret > 0) + ret = 1; + else + ret = 0; + + return ret; +} + +int BIO_puts(BIO *b, const char *buf) +{ + int ret; + size_t written = 0; + + if ((b == NULL) || (b->method == NULL) || (b->method->bputs == NULL)) { + BIOerr(BIO_F_BIO_PUTS, BIO_R_UNSUPPORTED_METHOD); + return -2; + } + + if (b->callback != NULL || b->callback_ex != NULL) { + ret = (int)bio_call_callback(b, BIO_CB_PUTS, buf, 0, 0, 0L, 1L, NULL); + if (ret <= 0) + return ret; + } + + if (!b->init) { + BIOerr(BIO_F_BIO_PUTS, BIO_R_UNINITIALIZED); + return -2; + } + + ret = b->method->bputs(b, buf); + + if (ret > 0) { + b->num_write += (uint64_t)ret; + written = ret; + ret = 1; + } + + if (b->callback != NULL || b->callback_ex != NULL) + ret = (int)bio_call_callback(b, BIO_CB_PUTS | BIO_CB_RETURN, buf, 0, 0, + 0L, ret, &written); + + if (ret > 0) { + if (written > INT_MAX) { + BIOerr(BIO_F_BIO_PUTS, BIO_R_LENGTH_TOO_LONG); + ret = -1; + } else { + ret = (int)written; + } + } + + return ret; +} + +int BIO_gets(BIO *b, char *buf, int size) +{ + int ret; + size_t readbytes = 0; + + if ((b == NULL) || (b->method == NULL) || (b->method->bgets == NULL)) { + BIOerr(BIO_F_BIO_GETS, BIO_R_UNSUPPORTED_METHOD); + return -2; + } + + if (size < 0) { + BIOerr(BIO_F_BIO_GETS, BIO_R_INVALID_ARGUMENT); + return 0; + } + + if (b->callback != NULL || b->callback_ex != NULL) { + ret = (int)bio_call_callback(b, BIO_CB_GETS, buf, size, 0, 0L, 1, NULL); + if (ret <= 0) + return ret; + } + + if (!b->init) { + BIOerr(BIO_F_BIO_GETS, BIO_R_UNINITIALIZED); + return -2; + } + + ret = b->method->bgets(b, buf, size); + + if (ret > 0) { + readbytes = ret; + ret = 1; + } + + if (b->callback != NULL || b->callback_ex != NULL) + ret = (int)bio_call_callback(b, BIO_CB_GETS | BIO_CB_RETURN, buf, size, + 0, 0L, ret, &readbytes); + + if (ret > 0) { + /* Shouldn't happen */ + if (readbytes > (size_t)size) + ret = -1; + else + ret = (int)readbytes; + } + + return ret; +} + +int BIO_indent(BIO *b, int indent, int max) +{ + if (indent < 0) + indent = 0; + if (indent > max) + indent = max; + while (indent--) + if (BIO_puts(b, " ") != 1) + return 0; + return 1; +} + +long BIO_int_ctrl(BIO *b, int cmd, long larg, int iarg) +{ + int i; + + i = iarg; + return BIO_ctrl(b, cmd, larg, (char *)&i); +} + +void *BIO_ptr_ctrl(BIO *b, int cmd, long larg) +{ + void *p = NULL; + + if (BIO_ctrl(b, cmd, larg, (char *)&p) <= 0) + return NULL; + else + return p; +} + +long BIO_ctrl(BIO *b, int cmd, long larg, void *parg) +{ + long ret; + + if (b == NULL) + return 0; + + if ((b->method == NULL) || (b->method->ctrl == NULL)) { + BIOerr(BIO_F_BIO_CTRL, BIO_R_UNSUPPORTED_METHOD); + return -2; + } + + if (b->callback != NULL || b->callback_ex != NULL) { + ret = bio_call_callback(b, BIO_CB_CTRL, parg, 0, cmd, larg, 1L, NULL); + if (ret <= 0) + return ret; + } + + ret = b->method->ctrl(b, cmd, larg, parg); + + if (b->callback != NULL || b->callback_ex != NULL) + ret = bio_call_callback(b, BIO_CB_CTRL | BIO_CB_RETURN, parg, 0, cmd, + larg, ret, NULL); + + return ret; +} + +long BIO_callback_ctrl(BIO *b, int cmd, BIO_info_cb *fp) +{ + long ret; + + if (b == NULL) + return 0; + + if ((b->method == NULL) || (b->method->callback_ctrl == NULL) + || (cmd != BIO_CTRL_SET_CALLBACK)) { + BIOerr(BIO_F_BIO_CALLBACK_CTRL, BIO_R_UNSUPPORTED_METHOD); + return -2; + } + + if (b->callback != NULL || b->callback_ex != NULL) { + ret = bio_call_callback(b, BIO_CB_CTRL, (void *)&fp, 0, cmd, 0, 1L, + NULL); + if (ret <= 0) + return ret; + } + + ret = b->method->callback_ctrl(b, cmd, fp); + + if (b->callback != NULL || b->callback_ex != NULL) + ret = bio_call_callback(b, BIO_CB_CTRL | BIO_CB_RETURN, (void *)&fp, 0, + cmd, 0, ret, NULL); + + return ret; +} + +/* + * It is unfortunate to duplicate in functions what the BIO_(w)pending macros + * do; but those macros have inappropriate return type, and for interfacing + * from other programming languages, C macros aren't much of a help anyway. + */ +size_t BIO_ctrl_pending(BIO *bio) +{ + return BIO_ctrl(bio, BIO_CTRL_PENDING, 0, NULL); +} + +size_t BIO_ctrl_wpending(BIO *bio) +{ + return BIO_ctrl(bio, BIO_CTRL_WPENDING, 0, NULL); +} + +/* put the 'bio' on the end of b's list of operators */ +BIO *BIO_push(BIO *b, BIO *bio) +{ + BIO *lb; + + if (b == NULL) + return bio; + lb = b; + while (lb->next_bio != NULL) + lb = lb->next_bio; + lb->next_bio = bio; + if (bio != NULL) + bio->prev_bio = lb; + /* called to do internal processing */ + BIO_ctrl(b, BIO_CTRL_PUSH, 0, lb); + return b; +} + +/* Remove the first and return the rest */ +BIO *BIO_pop(BIO *b) +{ + BIO *ret; + + if (b == NULL) + return NULL; + ret = b->next_bio; + + BIO_ctrl(b, BIO_CTRL_POP, 0, b); + + if (b->prev_bio != NULL) + b->prev_bio->next_bio = b->next_bio; + if (b->next_bio != NULL) + b->next_bio->prev_bio = b->prev_bio; + + b->next_bio = NULL; + b->prev_bio = NULL; + return ret; +} + +BIO *BIO_get_retry_BIO(BIO *bio, int *reason) +{ + BIO *b, *last; + + b = last = bio; + for (;;) { + if (!BIO_should_retry(b)) + break; + last = b; + b = b->next_bio; + if (b == NULL) + break; + } + if (reason != NULL) + *reason = last->retry_reason; + return last; +} + +int BIO_get_retry_reason(BIO *bio) +{ + return bio->retry_reason; +} + +void BIO_set_retry_reason(BIO *bio, int reason) +{ + bio->retry_reason = reason; +} + +BIO *BIO_find_type(BIO *bio, int type) +{ + int mt, mask; + + if (bio == NULL) + return NULL; + mask = type & 0xff; + do { + if (bio->method != NULL) { + mt = bio->method->type; + + if (!mask) { + if (mt & type) + return bio; + } else if (mt == type) + return bio; + } + bio = bio->next_bio; + } while (bio != NULL); + return NULL; +} + +BIO *BIO_next(BIO *b) +{ + if (b == NULL) + return NULL; + return b->next_bio; +} + +void BIO_set_next(BIO *b, BIO *next) +{ + b->next_bio = next; +} + +void BIO_free_all(BIO *bio) +{ + BIO *b; + int ref; + + while (bio != NULL) { + b = bio; + ref = b->references; + bio = bio->next_bio; + BIO_free(b); + /* Since ref count > 1, don't free anyone else. */ + if (ref > 1) + break; + } +} + +BIO *BIO_dup_chain(BIO *in) +{ + BIO *ret = NULL, *eoc = NULL, *bio, *new_bio; + + for (bio = in; bio != NULL; bio = bio->next_bio) { + if ((new_bio = BIO_new(bio->method)) == NULL) + goto err; + new_bio->callback = bio->callback; + new_bio->callback_ex = bio->callback_ex; + new_bio->cb_arg = bio->cb_arg; + new_bio->init = bio->init; + new_bio->shutdown = bio->shutdown; + new_bio->flags = bio->flags; + + /* This will let SSL_s_sock() work with stdin/stdout */ + new_bio->num = bio->num; + + if (!BIO_dup_state(bio, (char *)new_bio)) { + BIO_free(new_bio); + goto err; + } + + /* copy app data */ + if (!CRYPTO_dup_ex_data(CRYPTO_EX_INDEX_BIO, &new_bio->ex_data, + &bio->ex_data)) { + BIO_free(new_bio); + goto err; + } + + if (ret == NULL) { + eoc = new_bio; + ret = eoc; + } else { + BIO_push(eoc, new_bio); + eoc = new_bio; + } + } + return ret; + err: + BIO_free_all(ret); + + return NULL; +} + +void BIO_copy_next_retry(BIO *b) +{ + BIO_set_flags(b, BIO_get_retry_flags(b->next_bio)); + b->retry_reason = b->next_bio->retry_reason; +} + +int BIO_set_ex_data(BIO *bio, int idx, void *data) +{ + return CRYPTO_set_ex_data(&(bio->ex_data), idx, data); +} + +void *BIO_get_ex_data(BIO *bio, int idx) +{ + return CRYPTO_get_ex_data(&(bio->ex_data), idx); +} + +uint64_t BIO_number_read(BIO *bio) +{ + if (bio) + return bio->num_read; + return 0; +} + +uint64_t BIO_number_written(BIO *bio) +{ + if (bio) + return bio->num_write; + return 0; +} + +void bio_free_ex_data(BIO *bio) +{ + CRYPTO_free_ex_data(CRYPTO_EX_INDEX_BIO, bio, &bio->ex_data); +} + +void bio_cleanup(void) +{ +#ifndef OPENSSL_NO_SOCK + bio_sock_cleanup_int(); + CRYPTO_THREAD_lock_free(bio_lookup_lock); + bio_lookup_lock = NULL; +#endif + CRYPTO_THREAD_lock_free(bio_type_lock); + bio_type_lock = NULL; +} diff --git a/roms/edk2/CryptoPkg/Library/OpensslLib/openssl/crypto/bio/bio_local.h b/roms/edk2/CryptoPkg/Library/OpensslLib/openssl/crypto/bio/bio_local.h new file mode 100644 index 000000000..8b2122129 --- /dev/null +++ b/roms/edk2/CryptoPkg/Library/OpensslLib/openssl/crypto/bio/bio_local.h @@ -0,0 +1,190 @@ +/* + * Copyright 2005-2016 The OpenSSL Project Authors. All Rights Reserved. + * + * Licensed under the OpenSSL license (the "License"). You may not use + * this file except in compliance with the License. You can obtain a copy + * in the file LICENSE in the source distribution or at + * https://www.openssl.org/source/license.html + */ + +#include "e_os.h" +#include "internal/sockets.h" +#include "internal/refcount.h" + +/* BEGIN BIO_ADDRINFO/BIO_ADDR stuff. */ + +#ifndef OPENSSL_NO_SOCK +/* + * Throughout this file and b_addr.c, the existence of the macro + * AI_PASSIVE is used to detect the availability of struct addrinfo, + * getnameinfo() and getaddrinfo(). If that macro doesn't exist, + * we use our own implementation instead. + */ + +/* + * It's imperative that these macros get defined before openssl/bio.h gets + * included. Otherwise, the AI_PASSIVE hack will not work properly. + * For clarity, we check for internal/cryptlib.h since it's a common header + * that also includes bio.h. + */ +# ifdef OSSL_INTERNAL_CRYPTLIB_H +# error internal/cryptlib.h included before bio_local.h +# endif +# ifdef HEADER_BIO_H +# error openssl/bio.h included before bio_local.h +# endif + +/* + * Undefine AF_UNIX on systems that define it but don't support it. + */ +# if defined(OPENSSL_SYS_WINDOWS) || defined(OPENSSL_SYS_VMS) +# undef AF_UNIX +# endif + +# ifdef AI_PASSIVE + +/* + * There's a bug in VMS C header file netdb.h, where struct addrinfo + * always is the P32 variant, but the functions that handle that structure, + * such as getaddrinfo() and freeaddrinfo() adapt to the initial pointer + * size. The easiest workaround is to force struct addrinfo to be the + * 64-bit variant when compiling in P64 mode. + */ +# if defined(OPENSSL_SYS_VMS) && __INITIAL_POINTER_SIZE == 64 +# define addrinfo __addrinfo64 +# endif + +# define bio_addrinfo_st addrinfo +# define bai_family ai_family +# define bai_socktype ai_socktype +# define bai_protocol ai_protocol +# define bai_addrlen ai_addrlen +# define bai_addr ai_addr +# define bai_next ai_next +# else +struct bio_addrinfo_st { + int bai_family; + int bai_socktype; + int bai_protocol; + size_t bai_addrlen; + struct sockaddr *bai_addr; + struct bio_addrinfo_st *bai_next; +}; +# endif + +union bio_addr_st { + struct sockaddr sa; +# ifdef AF_INET6 + struct sockaddr_in6 s_in6; +# endif + struct sockaddr_in s_in; +# ifdef AF_UNIX + struct sockaddr_un s_un; +# endif +}; +#endif + +/* END BIO_ADDRINFO/BIO_ADDR stuff. */ + +#include "internal/cryptlib.h" +#include "internal/bio.h" + +typedef struct bio_f_buffer_ctx_struct { + /*- + * Buffers are setup like this: + * + * <---------------------- size -----------------------> + * +---------------------------------------------------+ + * | consumed | remaining | free space | + * +---------------------------------------------------+ + * <-- off --><------- len -------> + */ + /*- BIO *bio; *//* + * this is now in the BIO struct + */ + int ibuf_size; /* how big is the input buffer */ + int obuf_size; /* how big is the output buffer */ + char *ibuf; /* the char array */ + int ibuf_len; /* how many bytes are in it */ + int ibuf_off; /* write/read offset */ + char *obuf; /* the char array */ + int obuf_len; /* how many bytes are in it */ + int obuf_off; /* write/read offset */ +} BIO_F_BUFFER_CTX; + +struct bio_st { + const BIO_METHOD *method; + /* bio, mode, argp, argi, argl, ret */ + BIO_callback_fn callback; + BIO_callback_fn_ex callback_ex; + char *cb_arg; /* first argument for the callback */ + int init; + int shutdown; + int flags; /* extra storage */ + int retry_reason; + int num; + void *ptr; + struct bio_st *next_bio; /* used by filter BIOs */ + struct bio_st *prev_bio; /* used by filter BIOs */ + CRYPTO_REF_COUNT references; + uint64_t num_read; + uint64_t num_write; + CRYPTO_EX_DATA ex_data; + CRYPTO_RWLOCK *lock; +}; + +#ifndef OPENSSL_NO_SOCK +# ifdef OPENSSL_SYS_VMS +typedef unsigned int socklen_t; +# endif + +extern CRYPTO_RWLOCK *bio_lookup_lock; + +int BIO_ADDR_make(BIO_ADDR *ap, const struct sockaddr *sa); +const struct sockaddr *BIO_ADDR_sockaddr(const BIO_ADDR *ap); +struct sockaddr *BIO_ADDR_sockaddr_noconst(BIO_ADDR *ap); +socklen_t BIO_ADDR_sockaddr_size(const BIO_ADDR *ap); +socklen_t BIO_ADDRINFO_sockaddr_size(const BIO_ADDRINFO *bai); +const struct sockaddr *BIO_ADDRINFO_sockaddr(const BIO_ADDRINFO *bai); +#endif + +extern CRYPTO_RWLOCK *bio_type_lock; + +void bio_sock_cleanup_int(void); + +#if BIO_FLAGS_UPLINK==0 +/* Shortcut UPLINK calls on most platforms... */ +# define UP_stdin stdin +# define UP_stdout stdout +# define UP_stderr stderr +# define UP_fprintf fprintf +# define UP_fgets fgets +# define UP_fread fread +# define UP_fwrite fwrite +# undef UP_fsetmod +# define UP_feof feof +# define UP_fclose fclose + +# define UP_fopen fopen +# define UP_fseek fseek +# define UP_ftell ftell +# define UP_fflush fflush +# define UP_ferror ferror +# ifdef _WIN32 +# define UP_fileno _fileno +# define UP_open _open +# define UP_read _read +# define UP_write _write +# define UP_lseek _lseek +# define UP_close _close +# else +# define UP_fileno fileno +# define UP_open open +# define UP_read read +# define UP_write write +# define UP_lseek lseek +# define UP_close close +# endif + +#endif + diff --git a/roms/edk2/CryptoPkg/Library/OpensslLib/openssl/crypto/bio/bio_meth.c b/roms/edk2/CryptoPkg/Library/OpensslLib/openssl/crypto/bio/bio_meth.c new file mode 100644 index 000000000..da1164619 --- /dev/null +++ b/roms/edk2/CryptoPkg/Library/OpensslLib/openssl/crypto/bio/bio_meth.c @@ -0,0 +1,220 @@ +/* + * Copyright 2016-2018 The OpenSSL Project Authors. All Rights Reserved. + * + * Licensed under the OpenSSL license (the "License"). You may not use + * this file except in compliance with the License. You can obtain a copy + * in the file LICENSE in the source distribution or at + * https://www.openssl.org/source/license.html + */ + +#include "bio_local.h" +#include "internal/thread_once.h" + +CRYPTO_RWLOCK *bio_type_lock = NULL; +static CRYPTO_ONCE bio_type_init = CRYPTO_ONCE_STATIC_INIT; + +DEFINE_RUN_ONCE_STATIC(do_bio_type_init) +{ + bio_type_lock = CRYPTO_THREAD_lock_new(); + return bio_type_lock != NULL; +} + +int BIO_get_new_index(void) +{ + static CRYPTO_REF_COUNT bio_count = BIO_TYPE_START; + int newval; + + if (!RUN_ONCE(&bio_type_init, do_bio_type_init)) { + BIOerr(BIO_F_BIO_GET_NEW_INDEX, ERR_R_MALLOC_FAILURE); + return -1; + } + if (!CRYPTO_UP_REF(&bio_count, &newval, bio_type_lock)) + return -1; + return newval; +} + +BIO_METHOD *BIO_meth_new(int type, const char *name) +{ + BIO_METHOD *biom = OPENSSL_zalloc(sizeof(BIO_METHOD)); + + if (biom == NULL + || (biom->name = OPENSSL_strdup(name)) == NULL) { + OPENSSL_free(biom); + BIOerr(BIO_F_BIO_METH_NEW, ERR_R_MALLOC_FAILURE); + return NULL; + } + biom->type = type; + return biom; +} + +void BIO_meth_free(BIO_METHOD *biom) +{ + if (biom != NULL) { + OPENSSL_free(biom->name); + OPENSSL_free(biom); + } +} + +int (*BIO_meth_get_write(const BIO_METHOD *biom)) (BIO *, const char *, int) +{ + return biom->bwrite_old; +} + +int (*BIO_meth_get_write_ex(const BIO_METHOD *biom)) (BIO *, const char *, size_t, + size_t *) +{ + return biom->bwrite; +} + +/* Conversion for old style bwrite to new style */ +int bwrite_conv(BIO *bio, const char *data, size_t datal, size_t *written) +{ + int ret; + + if (datal > INT_MAX) + datal = INT_MAX; + + ret = bio->method->bwrite_old(bio, data, (int)datal); + + if (ret <= 0) { + *written = 0; + return ret; + } + + *written = (size_t)ret; + + return 1; +} + +int BIO_meth_set_write(BIO_METHOD *biom, + int (*bwrite) (BIO *, const char *, int)) +{ + biom->bwrite_old = bwrite; + biom->bwrite = bwrite_conv; + return 1; +} + +int BIO_meth_set_write_ex(BIO_METHOD *biom, + int (*bwrite) (BIO *, const char *, size_t, size_t *)) +{ + biom->bwrite_old = NULL; + biom->bwrite = bwrite; + return 1; +} + +int (*BIO_meth_get_read(const BIO_METHOD *biom)) (BIO *, char *, int) +{ + return biom->bread_old; +} + +int (*BIO_meth_get_read_ex(const BIO_METHOD *biom)) (BIO *, char *, size_t, size_t *) +{ + return biom->bread; +} + +/* Conversion for old style bread to new style */ +int bread_conv(BIO *bio, char *data, size_t datal, size_t *readbytes) +{ + int ret; + + if (datal > INT_MAX) + datal = INT_MAX; + + ret = bio->method->bread_old(bio, data, (int)datal); + + if (ret <= 0) { + *readbytes = 0; + return ret; + } + + *readbytes = (size_t)ret; + + return 1; +} + +int BIO_meth_set_read(BIO_METHOD *biom, + int (*bread) (BIO *, char *, int)) +{ + biom->bread_old = bread; + biom->bread = bread_conv; + return 1; +} + +int BIO_meth_set_read_ex(BIO_METHOD *biom, + int (*bread) (BIO *, char *, size_t, size_t *)) +{ + biom->bread_old = NULL; + biom->bread = bread; + return 1; +} + +int (*BIO_meth_get_puts(const BIO_METHOD *biom)) (BIO *, const char *) +{ + return biom->bputs; +} + +int BIO_meth_set_puts(BIO_METHOD *biom, + int (*bputs) (BIO *, const char *)) +{ + biom->bputs = bputs; + return 1; +} + +int (*BIO_meth_get_gets(const BIO_METHOD *biom)) (BIO *, char *, int) +{ + return biom->bgets; +} + +int BIO_meth_set_gets(BIO_METHOD *biom, + int (*bgets) (BIO *, char *, int)) +{ + biom->bgets = bgets; + return 1; +} + +long (*BIO_meth_get_ctrl(const BIO_METHOD *biom)) (BIO *, int, long, void *) +{ + return biom->ctrl; +} + +int BIO_meth_set_ctrl(BIO_METHOD *biom, + long (*ctrl) (BIO *, int, long, void *)) +{ + biom->ctrl = ctrl; + return 1; +} + +int (*BIO_meth_get_create(const BIO_METHOD *biom)) (BIO *) +{ + return biom->create; +} + +int BIO_meth_set_create(BIO_METHOD *biom, int (*create) (BIO *)) +{ + biom->create = create; + return 1; +} + +int (*BIO_meth_get_destroy(const BIO_METHOD *biom)) (BIO *) +{ + return biom->destroy; +} + +int BIO_meth_set_destroy(BIO_METHOD *biom, int (*destroy) (BIO *)) +{ + biom->destroy = destroy; + return 1; +} + +long (*BIO_meth_get_callback_ctrl(const BIO_METHOD *biom)) (BIO *, int, BIO_info_cb *) +{ + return biom->callback_ctrl; +} + +int BIO_meth_set_callback_ctrl(BIO_METHOD *biom, + long (*callback_ctrl) (BIO *, int, + BIO_info_cb *)) +{ + biom->callback_ctrl = callback_ctrl; + return 1; +} diff --git a/roms/edk2/CryptoPkg/Library/OpensslLib/openssl/crypto/bio/bss_acpt.c b/roms/edk2/CryptoPkg/Library/OpensslLib/openssl/crypto/bio/bss_acpt.c new file mode 100644 index 000000000..5a2cb50df --- /dev/null +++ b/roms/edk2/CryptoPkg/Library/OpensslLib/openssl/crypto/bio/bss_acpt.c @@ -0,0 +1,566 @@ +/* + * Copyright 1995-2020 The OpenSSL Project Authors. All Rights Reserved. + * + * Licensed under the OpenSSL license (the "License"). You may not use + * this file except in compliance with the License. You can obtain a copy + * in the file LICENSE in the source distribution or at + * https://www.openssl.org/source/license.html + */ + +#include <stdio.h> +#include <errno.h> +#include "bio_local.h" + +#ifndef OPENSSL_NO_SOCK + +typedef struct bio_accept_st { + int state; + int accept_family; + int bind_mode; /* Socket mode for BIO_listen */ + int accepted_mode; /* Socket mode for BIO_accept (set on accepted sock) */ + char *param_addr; + char *param_serv; + + int accept_sock; + + BIO_ADDRINFO *addr_first; + const BIO_ADDRINFO *addr_iter; + BIO_ADDR cache_accepting_addr; /* Useful if we asked for port 0 */ + char *cache_accepting_name, *cache_accepting_serv; + BIO_ADDR cache_peer_addr; + char *cache_peer_name, *cache_peer_serv; + + BIO *bio_chain; +} BIO_ACCEPT; + +static int acpt_write(BIO *h, const char *buf, int num); +static int acpt_read(BIO *h, char *buf, int size); +static int acpt_puts(BIO *h, const char *str); +static long acpt_ctrl(BIO *h, int cmd, long arg1, void *arg2); +static int acpt_new(BIO *h); +static int acpt_free(BIO *data); +static int acpt_state(BIO *b, BIO_ACCEPT *c); +static void acpt_close_socket(BIO *data); +static BIO_ACCEPT *BIO_ACCEPT_new(void); +static void BIO_ACCEPT_free(BIO_ACCEPT *a); + +# define ACPT_S_BEFORE 1 +# define ACPT_S_GET_ADDR 2 +# define ACPT_S_CREATE_SOCKET 3 +# define ACPT_S_LISTEN 4 +# define ACPT_S_ACCEPT 5 +# define ACPT_S_OK 6 + +static const BIO_METHOD methods_acceptp = { + BIO_TYPE_ACCEPT, + "socket accept", + /* TODO: Convert to new style write function */ + bwrite_conv, + acpt_write, + /* TODO: Convert to new style read function */ + bread_conv, + acpt_read, + acpt_puts, + NULL, /* connect_gets, */ + acpt_ctrl, + acpt_new, + acpt_free, + NULL, /* connect_callback_ctrl */ +}; + +const BIO_METHOD *BIO_s_accept(void) +{ + return &methods_acceptp; +} + +static int acpt_new(BIO *bi) +{ + BIO_ACCEPT *ba; + + bi->init = 0; + bi->num = (int)INVALID_SOCKET; + bi->flags = 0; + if ((ba = BIO_ACCEPT_new()) == NULL) + return 0; + bi->ptr = (char *)ba; + ba->state = ACPT_S_BEFORE; + bi->shutdown = 1; + return 1; +} + +static BIO_ACCEPT *BIO_ACCEPT_new(void) +{ + BIO_ACCEPT *ret; + + if ((ret = OPENSSL_zalloc(sizeof(*ret))) == NULL) { + BIOerr(BIO_F_BIO_ACCEPT_NEW, ERR_R_MALLOC_FAILURE); + return NULL; + } + ret->accept_family = BIO_FAMILY_IPANY; + ret->accept_sock = (int)INVALID_SOCKET; + return ret; +} + +static void BIO_ACCEPT_free(BIO_ACCEPT *a) +{ + if (a == NULL) + return; + OPENSSL_free(a->param_addr); + OPENSSL_free(a->param_serv); + BIO_ADDRINFO_free(a->addr_first); + OPENSSL_free(a->cache_accepting_name); + OPENSSL_free(a->cache_accepting_serv); + OPENSSL_free(a->cache_peer_name); + OPENSSL_free(a->cache_peer_serv); + BIO_free(a->bio_chain); + OPENSSL_free(a); +} + +static void acpt_close_socket(BIO *bio) +{ + BIO_ACCEPT *c; + + c = (BIO_ACCEPT *)bio->ptr; + if (c->accept_sock != (int)INVALID_SOCKET) { + shutdown(c->accept_sock, 2); + closesocket(c->accept_sock); + c->accept_sock = (int)INVALID_SOCKET; + bio->num = (int)INVALID_SOCKET; + } +} + +static int acpt_free(BIO *a) +{ + BIO_ACCEPT *data; + + if (a == NULL) + return 0; + data = (BIO_ACCEPT *)a->ptr; + + if (a->shutdown) { + acpt_close_socket(a); + BIO_ACCEPT_free(data); + a->ptr = NULL; + a->flags = 0; + a->init = 0; + } + return 1; +} + +static int acpt_state(BIO *b, BIO_ACCEPT *c) +{ + BIO *bio = NULL, *dbio; + int s = -1, ret = -1; + + for (;;) { + switch (c->state) { + case ACPT_S_BEFORE: + if (c->param_addr == NULL && c->param_serv == NULL) { + BIOerr(BIO_F_ACPT_STATE, BIO_R_NO_ACCEPT_ADDR_OR_SERVICE_SPECIFIED); + ERR_add_error_data(4, + "hostname=", c->param_addr, + " service=", c->param_serv); + goto exit_loop; + } + + /* Because we're starting a new bind, any cached name and serv + * are now obsolete and need to be cleaned out. + * QUESTION: should this be done in acpt_close_socket() instead? + */ + OPENSSL_free(c->cache_accepting_name); + c->cache_accepting_name = NULL; + OPENSSL_free(c->cache_accepting_serv); + c->cache_accepting_serv = NULL; + OPENSSL_free(c->cache_peer_name); + c->cache_peer_name = NULL; + OPENSSL_free(c->cache_peer_serv); + c->cache_peer_serv = NULL; + + c->state = ACPT_S_GET_ADDR; + break; + + case ACPT_S_GET_ADDR: + { + int family = AF_UNSPEC; + switch (c->accept_family) { + case BIO_FAMILY_IPV6: + if (1) { /* This is a trick we use to avoid bit rot. + * at least the "else" part will always be + * compiled. + */ +#ifdef AF_INET6 + family = AF_INET6; + } else { +#endif + BIOerr(BIO_F_ACPT_STATE, BIO_R_UNAVAILABLE_IP_FAMILY); + goto exit_loop; + } + break; + case BIO_FAMILY_IPV4: + family = AF_INET; + break; + case BIO_FAMILY_IPANY: + family = AF_UNSPEC; + break; + default: + BIOerr(BIO_F_ACPT_STATE, BIO_R_UNSUPPORTED_IP_FAMILY); + goto exit_loop; + } + if (BIO_lookup(c->param_addr, c->param_serv, BIO_LOOKUP_SERVER, + family, SOCK_STREAM, &c->addr_first) == 0) + goto exit_loop; + } + if (c->addr_first == NULL) { + BIOerr(BIO_F_ACPT_STATE, BIO_R_LOOKUP_RETURNED_NOTHING); + goto exit_loop; + } + /* We're currently not iterating, but set this as preparation + * for possible future development in that regard + */ + c->addr_iter = c->addr_first; + c->state = ACPT_S_CREATE_SOCKET; + break; + + case ACPT_S_CREATE_SOCKET: + s = BIO_socket(BIO_ADDRINFO_family(c->addr_iter), + BIO_ADDRINFO_socktype(c->addr_iter), + BIO_ADDRINFO_protocol(c->addr_iter), 0); + if (s == (int)INVALID_SOCKET) { + SYSerr(SYS_F_SOCKET, get_last_socket_error()); + ERR_add_error_data(4, + "hostname=", c->param_addr, + " service=", c->param_serv); + BIOerr(BIO_F_ACPT_STATE, BIO_R_UNABLE_TO_CREATE_SOCKET); + goto exit_loop; + } + c->accept_sock = s; + b->num = s; + c->state = ACPT_S_LISTEN; + s = -1; + break; + + case ACPT_S_LISTEN: + { + if (!BIO_listen(c->accept_sock, + BIO_ADDRINFO_address(c->addr_iter), + c->bind_mode)) { + BIO_closesocket(c->accept_sock); + goto exit_loop; + } + } + + { + union BIO_sock_info_u info; + + info.addr = &c->cache_accepting_addr; + if (!BIO_sock_info(c->accept_sock, BIO_SOCK_INFO_ADDRESS, + &info)) { + BIO_closesocket(c->accept_sock); + goto exit_loop; + } + } + + c->cache_accepting_name = + BIO_ADDR_hostname_string(&c->cache_accepting_addr, 1); + c->cache_accepting_serv = + BIO_ADDR_service_string(&c->cache_accepting_addr, 1); + c->state = ACPT_S_ACCEPT; + s = -1; + ret = 1; + goto end; + + case ACPT_S_ACCEPT: + if (b->next_bio != NULL) { + c->state = ACPT_S_OK; + break; + } + BIO_clear_retry_flags(b); + b->retry_reason = 0; + + OPENSSL_free(c->cache_peer_name); + c->cache_peer_name = NULL; + OPENSSL_free(c->cache_peer_serv); + c->cache_peer_serv = NULL; + + s = BIO_accept_ex(c->accept_sock, &c->cache_peer_addr, + c->accepted_mode); + + /* If the returned socket is invalid, this might still be + * retryable + */ + if (s < 0) { + if (BIO_sock_should_retry(s)) { + BIO_set_retry_special(b); + b->retry_reason = BIO_RR_ACCEPT; + goto end; + } + } + + /* If it wasn't retryable, we fail */ + if (s < 0) { + ret = s; + goto exit_loop; + } + + bio = BIO_new_socket(s, BIO_CLOSE); + if (bio == NULL) + goto exit_loop; + + BIO_set_callback(bio, BIO_get_callback(b)); + BIO_set_callback_arg(bio, BIO_get_callback_arg(b)); + + /* + * If the accept BIO has an bio_chain, we dup it and put the new + * socket at the end. + */ + if (c->bio_chain != NULL) { + if ((dbio = BIO_dup_chain(c->bio_chain)) == NULL) + goto exit_loop; + if (!BIO_push(dbio, bio)) + goto exit_loop; + bio = dbio; + } + if (BIO_push(b, bio) == NULL) + goto exit_loop; + + c->cache_peer_name = + BIO_ADDR_hostname_string(&c->cache_peer_addr, 1); + c->cache_peer_serv = + BIO_ADDR_service_string(&c->cache_peer_addr, 1); + c->state = ACPT_S_OK; + bio = NULL; + ret = 1; + goto end; + + case ACPT_S_OK: + if (b->next_bio == NULL) { + c->state = ACPT_S_ACCEPT; + break; + } + ret = 1; + goto end; + + default: + ret = 0; + goto end; + } + } + + exit_loop: + if (bio != NULL) + BIO_free(bio); + else if (s >= 0) + BIO_closesocket(s); + end: + return ret; +} + +static int acpt_read(BIO *b, char *out, int outl) +{ + int ret = 0; + BIO_ACCEPT *data; + + BIO_clear_retry_flags(b); + data = (BIO_ACCEPT *)b->ptr; + + while (b->next_bio == NULL) { + ret = acpt_state(b, data); + if (ret <= 0) + return ret; + } + + ret = BIO_read(b->next_bio, out, outl); + BIO_copy_next_retry(b); + return ret; +} + +static int acpt_write(BIO *b, const char *in, int inl) +{ + int ret; + BIO_ACCEPT *data; + + BIO_clear_retry_flags(b); + data = (BIO_ACCEPT *)b->ptr; + + while (b->next_bio == NULL) { + ret = acpt_state(b, data); + if (ret <= 0) + return ret; + } + + ret = BIO_write(b->next_bio, in, inl); + BIO_copy_next_retry(b); + return ret; +} + +static long acpt_ctrl(BIO *b, int cmd, long num, void *ptr) +{ + int *ip; + long ret = 1; + BIO_ACCEPT *data; + char **pp; + + data = (BIO_ACCEPT *)b->ptr; + + switch (cmd) { + case BIO_CTRL_RESET: + ret = 0; + data->state = ACPT_S_BEFORE; + acpt_close_socket(b); + BIO_ADDRINFO_free(data->addr_first); + data->addr_first = NULL; + b->flags = 0; + break; + case BIO_C_DO_STATE_MACHINE: + /* use this one to start the connection */ + ret = (long)acpt_state(b, data); + break; + case BIO_C_SET_ACCEPT: + if (ptr != NULL) { + if (num == 0) { + char *hold_serv = data->param_serv; + /* We affect the hostname regardless. However, the input + * string might contain a host:service spec, so we must + * parse it, which might or might not affect the service + */ + OPENSSL_free(data->param_addr); + data->param_addr = NULL; + ret = BIO_parse_hostserv(ptr, + &data->param_addr, + &data->param_serv, + BIO_PARSE_PRIO_SERV); + if (hold_serv != data->param_serv) + OPENSSL_free(hold_serv); + b->init = 1; + } else if (num == 1) { + OPENSSL_free(data->param_serv); + data->param_serv = BUF_strdup(ptr); + b->init = 1; + } else if (num == 2) { + data->bind_mode |= BIO_SOCK_NONBLOCK; + } else if (num == 3) { + BIO_free(data->bio_chain); + data->bio_chain = (BIO *)ptr; + } else if (num == 4) { + data->accept_family = *(int *)ptr; + } + } else { + if (num == 2) { + data->bind_mode &= ~BIO_SOCK_NONBLOCK; + } + } + break; + case BIO_C_SET_NBIO: + if (num != 0) + data->accepted_mode |= BIO_SOCK_NONBLOCK; + else + data->accepted_mode &= ~BIO_SOCK_NONBLOCK; + break; + case BIO_C_SET_FD: + b->num = *((int *)ptr); + data->accept_sock = b->num; + data->state = ACPT_S_ACCEPT; + b->shutdown = (int)num; + b->init = 1; + break; + case BIO_C_GET_FD: + if (b->init) { + ip = (int *)ptr; + if (ip != NULL) + *ip = data->accept_sock; + ret = data->accept_sock; + } else + ret = -1; + break; + case BIO_C_GET_ACCEPT: + if (b->init) { + if (num == 0 && ptr != NULL) { + pp = (char **)ptr; + *pp = data->cache_accepting_name; + } else if (num == 1 && ptr != NULL) { + pp = (char **)ptr; + *pp = data->cache_accepting_serv; + } else if (num == 2 && ptr != NULL) { + pp = (char **)ptr; + *pp = data->cache_peer_name; + } else if (num == 3 && ptr != NULL) { + pp = (char **)ptr; + *pp = data->cache_peer_serv; + } else if (num == 4) { + switch (BIO_ADDRINFO_family(data->addr_iter)) { +#ifdef AF_INET6 + case AF_INET6: + ret = BIO_FAMILY_IPV6; + break; +#endif + case AF_INET: + ret = BIO_FAMILY_IPV4; + break; + case 0: + ret = data->accept_family; + break; + default: + ret = -1; + break; + } + } else + ret = -1; + } else + ret = -1; + break; + case BIO_CTRL_GET_CLOSE: + ret = b->shutdown; + break; + case BIO_CTRL_SET_CLOSE: + b->shutdown = (int)num; + break; + case BIO_CTRL_PENDING: + case BIO_CTRL_WPENDING: + ret = 0; + break; + case BIO_CTRL_FLUSH: + break; + case BIO_C_SET_BIND_MODE: + data->bind_mode = (int)num; + break; + case BIO_C_GET_BIND_MODE: + ret = (long)data->bind_mode; + break; + case BIO_CTRL_DUP: + break; + case BIO_CTRL_EOF: + if (b->next_bio == NULL) + ret = 0; + else + ret = BIO_ctrl(b->next_bio, cmd, num, ptr); + break; + default: + ret = 0; + break; + } + return ret; +} + +static int acpt_puts(BIO *bp, const char *str) +{ + int n, ret; + + n = strlen(str); + ret = acpt_write(bp, str, n); + return ret; +} + +BIO *BIO_new_accept(const char *str) +{ + BIO *ret; + + ret = BIO_new(BIO_s_accept()); + if (ret == NULL) + return NULL; + if (BIO_set_accept_name(ret, str)) + return ret; + BIO_free(ret); + return NULL; +} + +#endif diff --git a/roms/edk2/CryptoPkg/Library/OpensslLib/openssl/crypto/bio/bss_bio.c b/roms/edk2/CryptoPkg/Library/OpensslLib/openssl/crypto/bio/bss_bio.c new file mode 100644 index 000000000..c97349e43 --- /dev/null +++ b/roms/edk2/CryptoPkg/Library/OpensslLib/openssl/crypto/bio/bss_bio.c @@ -0,0 +1,808 @@ +/* + * Copyright 1999-2017 The OpenSSL Project Authors. All Rights Reserved. + * + * Licensed under the OpenSSL license (the "License"). You may not use + * this file except in compliance with the License. You can obtain a copy + * in the file LICENSE in the source distribution or at + * https://www.openssl.org/source/license.html + */ + +/* + * Special method for a BIO where the other endpoint is also a BIO of this + * kind, handled by the same thread (i.e. the "peer" is actually ourselves, + * wearing a different hat). Such "BIO pairs" are mainly for using the SSL + * library with I/O interfaces for which no specific BIO method is available. + * See ssl/ssltest.c for some hints on how this can be used. + */ + +#include "e_os.h" +#include <assert.h> +#include <limits.h> +#include <stdlib.h> +#include <string.h> + +#include "bio_local.h" +#include <openssl/err.h> +#include <openssl/crypto.h> + +static int bio_new(BIO *bio); +static int bio_free(BIO *bio); +static int bio_read(BIO *bio, char *buf, int size); +static int bio_write(BIO *bio, const char *buf, int num); +static long bio_ctrl(BIO *bio, int cmd, long num, void *ptr); +static int bio_puts(BIO *bio, const char *str); + +static int bio_make_pair(BIO *bio1, BIO *bio2); +static void bio_destroy_pair(BIO *bio); + +static const BIO_METHOD methods_biop = { + BIO_TYPE_BIO, + "BIO pair", + /* TODO: Convert to new style write function */ + bwrite_conv, + bio_write, + /* TODO: Convert to new style read function */ + bread_conv, + bio_read, + bio_puts, + NULL /* no bio_gets */ , + bio_ctrl, + bio_new, + bio_free, + NULL /* no bio_callback_ctrl */ +}; + +const BIO_METHOD *BIO_s_bio(void) +{ + return &methods_biop; +} + +struct bio_bio_st { + BIO *peer; /* NULL if buf == NULL. If peer != NULL, then + * peer->ptr is also a bio_bio_st, and its + * "peer" member points back to us. peer != + * NULL iff init != 0 in the BIO. */ + /* This is for what we write (i.e. reading uses peer's struct): */ + int closed; /* valid iff peer != NULL */ + size_t len; /* valid iff buf != NULL; 0 if peer == NULL */ + size_t offset; /* valid iff buf != NULL; 0 if len == 0 */ + size_t size; + char *buf; /* "size" elements (if != NULL) */ + size_t request; /* valid iff peer != NULL; 0 if len != 0, + * otherwise set by peer to number of bytes + * it (unsuccessfully) tried to read, never + * more than buffer space (size-len) + * warrants. */ +}; + +static int bio_new(BIO *bio) +{ + struct bio_bio_st *b = OPENSSL_zalloc(sizeof(*b)); + + if (b == NULL) + return 0; + + /* enough for one TLS record (just a default) */ + b->size = 17 * 1024; + + bio->ptr = b; + return 1; +} + +static int bio_free(BIO *bio) +{ + struct bio_bio_st *b; + + if (bio == NULL) + return 0; + b = bio->ptr; + + assert(b != NULL); + + if (b->peer) + bio_destroy_pair(bio); + + OPENSSL_free(b->buf); + OPENSSL_free(b); + + return 1; +} + +static int bio_read(BIO *bio, char *buf, int size_) +{ + size_t size = size_; + size_t rest; + struct bio_bio_st *b, *peer_b; + + BIO_clear_retry_flags(bio); + + if (!bio->init) + return 0; + + b = bio->ptr; + assert(b != NULL); + assert(b->peer != NULL); + peer_b = b->peer->ptr; + assert(peer_b != NULL); + assert(peer_b->buf != NULL); + + peer_b->request = 0; /* will be set in "retry_read" situation */ + + if (buf == NULL || size == 0) + return 0; + + if (peer_b->len == 0) { + if (peer_b->closed) + return 0; /* writer has closed, and no data is left */ + else { + BIO_set_retry_read(bio); /* buffer is empty */ + if (size <= peer_b->size) + peer_b->request = size; + else + /* + * don't ask for more than the peer can deliver in one write + */ + peer_b->request = peer_b->size; + return -1; + } + } + + /* we can read */ + if (peer_b->len < size) + size = peer_b->len; + + /* now read "size" bytes */ + + rest = size; + + assert(rest > 0); + do { /* one or two iterations */ + size_t chunk; + + assert(rest <= peer_b->len); + if (peer_b->offset + rest <= peer_b->size) + chunk = rest; + else + /* wrap around ring buffer */ + chunk = peer_b->size - peer_b->offset; + assert(peer_b->offset + chunk <= peer_b->size); + + memcpy(buf, peer_b->buf + peer_b->offset, chunk); + + peer_b->len -= chunk; + if (peer_b->len) { + peer_b->offset += chunk; + assert(peer_b->offset <= peer_b->size); + if (peer_b->offset == peer_b->size) + peer_b->offset = 0; + buf += chunk; + } else { + /* buffer now empty, no need to advance "buf" */ + assert(chunk == rest); + peer_b->offset = 0; + } + rest -= chunk; + } + while (rest); + + return size; +} + +/*- + * non-copying interface: provide pointer to available data in buffer + * bio_nread0: return number of available bytes + * bio_nread: also advance index + * (example usage: bio_nread0(), read from buffer, bio_nread() + * or just bio_nread(), read from buffer) + */ +/* + * WARNING: The non-copying interface is largely untested as of yet and may + * contain bugs. + */ +static ossl_ssize_t bio_nread0(BIO *bio, char **buf) +{ + struct bio_bio_st *b, *peer_b; + ossl_ssize_t num; + + BIO_clear_retry_flags(bio); + + if (!bio->init) + return 0; + + b = bio->ptr; + assert(b != NULL); + assert(b->peer != NULL); + peer_b = b->peer->ptr; + assert(peer_b != NULL); + assert(peer_b->buf != NULL); + + peer_b->request = 0; + + if (peer_b->len == 0) { + char dummy; + + /* avoid code duplication -- nothing available for reading */ + return bio_read(bio, &dummy, 1); /* returns 0 or -1 */ + } + + num = peer_b->len; + if (peer_b->size < peer_b->offset + num) + /* no ring buffer wrap-around for non-copying interface */ + num = peer_b->size - peer_b->offset; + assert(num > 0); + + if (buf != NULL) + *buf = peer_b->buf + peer_b->offset; + return num; +} + +static ossl_ssize_t bio_nread(BIO *bio, char **buf, size_t num_) +{ + struct bio_bio_st *b, *peer_b; + ossl_ssize_t num, available; + + if (num_ > OSSL_SSIZE_MAX) + num = OSSL_SSIZE_MAX; + else + num = (ossl_ssize_t) num_; + + available = bio_nread0(bio, buf); + if (num > available) + num = available; + if (num <= 0) + return num; + + b = bio->ptr; + peer_b = b->peer->ptr; + + peer_b->len -= num; + if (peer_b->len) { + peer_b->offset += num; + assert(peer_b->offset <= peer_b->size); + if (peer_b->offset == peer_b->size) + peer_b->offset = 0; + } else + peer_b->offset = 0; + + return num; +} + +static int bio_write(BIO *bio, const char *buf, int num_) +{ + size_t num = num_; + size_t rest; + struct bio_bio_st *b; + + BIO_clear_retry_flags(bio); + + if (!bio->init || buf == NULL || num == 0) + return 0; + + b = bio->ptr; + assert(b != NULL); + assert(b->peer != NULL); + assert(b->buf != NULL); + + b->request = 0; + if (b->closed) { + /* we already closed */ + BIOerr(BIO_F_BIO_WRITE, BIO_R_BROKEN_PIPE); + return -1; + } + + assert(b->len <= b->size); + + if (b->len == b->size) { + BIO_set_retry_write(bio); /* buffer is full */ + return -1; + } + + /* we can write */ + if (num > b->size - b->len) + num = b->size - b->len; + + /* now write "num" bytes */ + + rest = num; + + assert(rest > 0); + do { /* one or two iterations */ + size_t write_offset; + size_t chunk; + + assert(b->len + rest <= b->size); + + write_offset = b->offset + b->len; + if (write_offset >= b->size) + write_offset -= b->size; + /* b->buf[write_offset] is the first byte we can write to. */ + + if (write_offset + rest <= b->size) + chunk = rest; + else + /* wrap around ring buffer */ + chunk = b->size - write_offset; + + memcpy(b->buf + write_offset, buf, chunk); + + b->len += chunk; + + assert(b->len <= b->size); + + rest -= chunk; + buf += chunk; + } + while (rest); + + return num; +} + +/*- + * non-copying interface: provide pointer to region to write to + * bio_nwrite0: check how much space is available + * bio_nwrite: also increase length + * (example usage: bio_nwrite0(), write to buffer, bio_nwrite() + * or just bio_nwrite(), write to buffer) + */ +static ossl_ssize_t bio_nwrite0(BIO *bio, char **buf) +{ + struct bio_bio_st *b; + size_t num; + size_t write_offset; + + BIO_clear_retry_flags(bio); + + if (!bio->init) + return 0; + + b = bio->ptr; + assert(b != NULL); + assert(b->peer != NULL); + assert(b->buf != NULL); + + b->request = 0; + if (b->closed) { + BIOerr(BIO_F_BIO_NWRITE0, BIO_R_BROKEN_PIPE); + return -1; + } + + assert(b->len <= b->size); + + if (b->len == b->size) { + BIO_set_retry_write(bio); + return -1; + } + + num = b->size - b->len; + write_offset = b->offset + b->len; + if (write_offset >= b->size) + write_offset -= b->size; + if (write_offset + num > b->size) + /* + * no ring buffer wrap-around for non-copying interface (to fulfil + * the promise by BIO_ctrl_get_write_guarantee, BIO_nwrite may have + * to be called twice) + */ + num = b->size - write_offset; + + if (buf != NULL) + *buf = b->buf + write_offset; + assert(write_offset + num <= b->size); + + return num; +} + +static ossl_ssize_t bio_nwrite(BIO *bio, char **buf, size_t num_) +{ + struct bio_bio_st *b; + ossl_ssize_t num, space; + + if (num_ > OSSL_SSIZE_MAX) + num = OSSL_SSIZE_MAX; + else + num = (ossl_ssize_t) num_; + + space = bio_nwrite0(bio, buf); + if (num > space) + num = space; + if (num <= 0) + return num; + b = bio->ptr; + assert(b != NULL); + b->len += num; + assert(b->len <= b->size); + + return num; +} + +static long bio_ctrl(BIO *bio, int cmd, long num, void *ptr) +{ + long ret; + struct bio_bio_st *b = bio->ptr; + + assert(b != NULL); + + switch (cmd) { + /* specific CTRL codes */ + + case BIO_C_SET_WRITE_BUF_SIZE: + if (b->peer) { + BIOerr(BIO_F_BIO_CTRL, BIO_R_IN_USE); + ret = 0; + } else if (num == 0) { + BIOerr(BIO_F_BIO_CTRL, BIO_R_INVALID_ARGUMENT); + ret = 0; + } else { + size_t new_size = num; + + if (b->size != new_size) { + OPENSSL_free(b->buf); + b->buf = NULL; + b->size = new_size; + } + ret = 1; + } + break; + + case BIO_C_GET_WRITE_BUF_SIZE: + ret = (long)b->size; + break; + + case BIO_C_MAKE_BIO_PAIR: + { + BIO *other_bio = ptr; + + if (bio_make_pair(bio, other_bio)) + ret = 1; + else + ret = 0; + } + break; + + case BIO_C_DESTROY_BIO_PAIR: + /* + * Affects both BIOs in the pair -- call just once! Or let + * BIO_free(bio1); BIO_free(bio2); do the job. + */ + bio_destroy_pair(bio); + ret = 1; + break; + + case BIO_C_GET_WRITE_GUARANTEE: + /* + * How many bytes can the caller feed to the next write without + * having to keep any? + */ + if (b->peer == NULL || b->closed) + ret = 0; + else + ret = (long)b->size - b->len; + break; + + case BIO_C_GET_READ_REQUEST: + /* + * If the peer unsuccessfully tried to read, how many bytes were + * requested? (As with BIO_CTRL_PENDING, that number can usually be + * treated as boolean.) + */ + ret = (long)b->request; + break; + + case BIO_C_RESET_READ_REQUEST: + /* + * Reset request. (Can be useful after read attempts at the other + * side that are meant to be non-blocking, e.g. when probing SSL_read + * to see if any data is available.) + */ + b->request = 0; + ret = 1; + break; + + case BIO_C_SHUTDOWN_WR: + /* similar to shutdown(..., SHUT_WR) */ + b->closed = 1; + ret = 1; + break; + + case BIO_C_NREAD0: + /* prepare for non-copying read */ + ret = (long)bio_nread0(bio, ptr); + break; + + case BIO_C_NREAD: + /* non-copying read */ + ret = (long)bio_nread(bio, ptr, (size_t)num); + break; + + case BIO_C_NWRITE0: + /* prepare for non-copying write */ + ret = (long)bio_nwrite0(bio, ptr); + break; + + case BIO_C_NWRITE: + /* non-copying write */ + ret = (long)bio_nwrite(bio, ptr, (size_t)num); + break; + + /* standard CTRL codes follow */ + + case BIO_CTRL_RESET: + if (b->buf != NULL) { + b->len = 0; + b->offset = 0; + } + ret = 0; + break; + + case BIO_CTRL_GET_CLOSE: + ret = bio->shutdown; + break; + + case BIO_CTRL_SET_CLOSE: + bio->shutdown = (int)num; + ret = 1; + break; + + case BIO_CTRL_PENDING: + if (b->peer != NULL) { + struct bio_bio_st *peer_b = b->peer->ptr; + + ret = (long)peer_b->len; + } else + ret = 0; + break; + + case BIO_CTRL_WPENDING: + if (b->buf != NULL) + ret = (long)b->len; + else + ret = 0; + break; + + case BIO_CTRL_DUP: + /* See BIO_dup_chain for circumstances we have to expect. */ + { + BIO *other_bio = ptr; + struct bio_bio_st *other_b; + + assert(other_bio != NULL); + other_b = other_bio->ptr; + assert(other_b != NULL); + + assert(other_b->buf == NULL); /* other_bio is always fresh */ + + other_b->size = b->size; + } + + ret = 1; + break; + + case BIO_CTRL_FLUSH: + ret = 1; + break; + + case BIO_CTRL_EOF: + if (b->peer != NULL) { + struct bio_bio_st *peer_b = b->peer->ptr; + + if (peer_b->len == 0 && peer_b->closed) + ret = 1; + else + ret = 0; + } else { + ret = 1; + } + break; + + default: + ret = 0; + } + return ret; +} + +static int bio_puts(BIO *bio, const char *str) +{ + return bio_write(bio, str, strlen(str)); +} + +static int bio_make_pair(BIO *bio1, BIO *bio2) +{ + struct bio_bio_st *b1, *b2; + + assert(bio1 != NULL); + assert(bio2 != NULL); + + b1 = bio1->ptr; + b2 = bio2->ptr; + + if (b1->peer != NULL || b2->peer != NULL) { + BIOerr(BIO_F_BIO_MAKE_PAIR, BIO_R_IN_USE); + return 0; + } + + if (b1->buf == NULL) { + b1->buf = OPENSSL_malloc(b1->size); + if (b1->buf == NULL) { + BIOerr(BIO_F_BIO_MAKE_PAIR, ERR_R_MALLOC_FAILURE); + return 0; + } + b1->len = 0; + b1->offset = 0; + } + + if (b2->buf == NULL) { + b2->buf = OPENSSL_malloc(b2->size); + if (b2->buf == NULL) { + BIOerr(BIO_F_BIO_MAKE_PAIR, ERR_R_MALLOC_FAILURE); + return 0; + } + b2->len = 0; + b2->offset = 0; + } + + b1->peer = bio2; + b1->closed = 0; + b1->request = 0; + b2->peer = bio1; + b2->closed = 0; + b2->request = 0; + + bio1->init = 1; + bio2->init = 1; + + return 1; +} + +static void bio_destroy_pair(BIO *bio) +{ + struct bio_bio_st *b = bio->ptr; + + if (b != NULL) { + BIO *peer_bio = b->peer; + + if (peer_bio != NULL) { + struct bio_bio_st *peer_b = peer_bio->ptr; + + assert(peer_b != NULL); + assert(peer_b->peer == bio); + + peer_b->peer = NULL; + peer_bio->init = 0; + assert(peer_b->buf != NULL); + peer_b->len = 0; + peer_b->offset = 0; + + b->peer = NULL; + bio->init = 0; + assert(b->buf != NULL); + b->len = 0; + b->offset = 0; + } + } +} + +/* Exported convenience functions */ +int BIO_new_bio_pair(BIO **bio1_p, size_t writebuf1, + BIO **bio2_p, size_t writebuf2) +{ + BIO *bio1 = NULL, *bio2 = NULL; + long r; + int ret = 0; + + bio1 = BIO_new(BIO_s_bio()); + if (bio1 == NULL) + goto err; + bio2 = BIO_new(BIO_s_bio()); + if (bio2 == NULL) + goto err; + + if (writebuf1) { + r = BIO_set_write_buf_size(bio1, writebuf1); + if (!r) + goto err; + } + if (writebuf2) { + r = BIO_set_write_buf_size(bio2, writebuf2); + if (!r) + goto err; + } + + r = BIO_make_bio_pair(bio1, bio2); + if (!r) + goto err; + ret = 1; + + err: + if (ret == 0) { + BIO_free(bio1); + bio1 = NULL; + BIO_free(bio2); + bio2 = NULL; + } + + *bio1_p = bio1; + *bio2_p = bio2; + return ret; +} + +size_t BIO_ctrl_get_write_guarantee(BIO *bio) +{ + return BIO_ctrl(bio, BIO_C_GET_WRITE_GUARANTEE, 0, NULL); +} + +size_t BIO_ctrl_get_read_request(BIO *bio) +{ + return BIO_ctrl(bio, BIO_C_GET_READ_REQUEST, 0, NULL); +} + +int BIO_ctrl_reset_read_request(BIO *bio) +{ + return (BIO_ctrl(bio, BIO_C_RESET_READ_REQUEST, 0, NULL) != 0); +} + +/* + * BIO_nread0/nread/nwrite0/nwrite are available only for BIO pairs for now + * (conceivably some other BIOs could allow non-copying reads and writes + * too.) + */ +int BIO_nread0(BIO *bio, char **buf) +{ + long ret; + + if (!bio->init) { + BIOerr(BIO_F_BIO_NREAD0, BIO_R_UNINITIALIZED); + return -2; + } + + ret = BIO_ctrl(bio, BIO_C_NREAD0, 0, buf); + if (ret > INT_MAX) + return INT_MAX; + else + return (int)ret; +} + +int BIO_nread(BIO *bio, char **buf, int num) +{ + int ret; + + if (!bio->init) { + BIOerr(BIO_F_BIO_NREAD, BIO_R_UNINITIALIZED); + return -2; + } + + ret = (int)BIO_ctrl(bio, BIO_C_NREAD, num, buf); + if (ret > 0) + bio->num_read += ret; + return ret; +} + +int BIO_nwrite0(BIO *bio, char **buf) +{ + long ret; + + if (!bio->init) { + BIOerr(BIO_F_BIO_NWRITE0, BIO_R_UNINITIALIZED); + return -2; + } + + ret = BIO_ctrl(bio, BIO_C_NWRITE0, 0, buf); + if (ret > INT_MAX) + return INT_MAX; + else + return (int)ret; +} + +int BIO_nwrite(BIO *bio, char **buf, int num) +{ + int ret; + + if (!bio->init) { + BIOerr(BIO_F_BIO_NWRITE, BIO_R_UNINITIALIZED); + return -2; + } + + ret = BIO_ctrl(bio, BIO_C_NWRITE, num, buf); + if (ret > 0) + bio->num_write += ret; + return ret; +} diff --git a/roms/edk2/CryptoPkg/Library/OpensslLib/openssl/crypto/bio/bss_conn.c b/roms/edk2/CryptoPkg/Library/OpensslLib/openssl/crypto/bio/bss_conn.c new file mode 100644 index 000000000..dd43a4060 --- /dev/null +++ b/roms/edk2/CryptoPkg/Library/OpensslLib/openssl/crypto/bio/bss_conn.c @@ -0,0 +1,552 @@ +/* + * Copyright 1995-2020 The OpenSSL Project Authors. All Rights Reserved. + * + * Licensed under the OpenSSL license (the "License"). You may not use + * this file except in compliance with the License. You can obtain a copy + * in the file LICENSE in the source distribution or at + * https://www.openssl.org/source/license.html + */ + +#include <stdio.h> +#include <errno.h> + +#include "bio_local.h" + +#ifndef OPENSSL_NO_SOCK + +typedef struct bio_connect_st { + int state; + int connect_family; + char *param_hostname; + char *param_service; + int connect_mode; + + BIO_ADDRINFO *addr_first; + const BIO_ADDRINFO *addr_iter; + /* + * int socket; this will be kept in bio->num so that it is compatible + * with the bss_sock bio + */ + /* + * called when the connection is initially made callback(BIO,state,ret); + * The callback should return 'ret'. state is for compatibility with the + * ssl info_callback + */ + BIO_info_cb *info_callback; +} BIO_CONNECT; + +static int conn_write(BIO *h, const char *buf, int num); +static int conn_read(BIO *h, char *buf, int size); +static int conn_puts(BIO *h, const char *str); +static long conn_ctrl(BIO *h, int cmd, long arg1, void *arg2); +static int conn_new(BIO *h); +static int conn_free(BIO *data); +static long conn_callback_ctrl(BIO *h, int cmd, BIO_info_cb *); + +static int conn_state(BIO *b, BIO_CONNECT *c); +static void conn_close_socket(BIO *data); +BIO_CONNECT *BIO_CONNECT_new(void); +void BIO_CONNECT_free(BIO_CONNECT *a); + +#define BIO_CONN_S_BEFORE 1 +#define BIO_CONN_S_GET_ADDR 2 +#define BIO_CONN_S_CREATE_SOCKET 3 +#define BIO_CONN_S_CONNECT 4 +#define BIO_CONN_S_OK 5 +#define BIO_CONN_S_BLOCKED_CONNECT 6 +#define BIO_CONN_S_CONNECT_ERROR 7 + +static const BIO_METHOD methods_connectp = { + BIO_TYPE_CONNECT, + "socket connect", + /* TODO: Convert to new style write function */ + bwrite_conv, + conn_write, + /* TODO: Convert to new style read function */ + bread_conv, + conn_read, + conn_puts, + NULL, /* conn_gets, */ + conn_ctrl, + conn_new, + conn_free, + conn_callback_ctrl, +}; + +static int conn_state(BIO *b, BIO_CONNECT *c) +{ + int ret = -1, i; + BIO_info_cb *cb = NULL; + + if (c->info_callback != NULL) + cb = c->info_callback; + + for (;;) { + switch (c->state) { + case BIO_CONN_S_BEFORE: + if (c->param_hostname == NULL && c->param_service == NULL) { + BIOerr(BIO_F_CONN_STATE, BIO_R_NO_HOSTNAME_OR_SERVICE_SPECIFIED); + ERR_add_error_data(4, + "hostname=", c->param_hostname, + " service=", c->param_service); + goto exit_loop; + } + c->state = BIO_CONN_S_GET_ADDR; + break; + + case BIO_CONN_S_GET_ADDR: + { + int family = AF_UNSPEC; + switch (c->connect_family) { + case BIO_FAMILY_IPV6: + if (1) { /* This is a trick we use to avoid bit rot. + * at least the "else" part will always be + * compiled. + */ +#ifdef AF_INET6 + family = AF_INET6; + } else { +#endif + BIOerr(BIO_F_CONN_STATE, BIO_R_UNAVAILABLE_IP_FAMILY); + goto exit_loop; + } + break; + case BIO_FAMILY_IPV4: + family = AF_INET; + break; + case BIO_FAMILY_IPANY: + family = AF_UNSPEC; + break; + default: + BIOerr(BIO_F_CONN_STATE, BIO_R_UNSUPPORTED_IP_FAMILY); + goto exit_loop; + } + if (BIO_lookup(c->param_hostname, c->param_service, + BIO_LOOKUP_CLIENT, + family, SOCK_STREAM, &c->addr_first) == 0) + goto exit_loop; + } + if (c->addr_first == NULL) { + BIOerr(BIO_F_CONN_STATE, BIO_R_LOOKUP_RETURNED_NOTHING); + goto exit_loop; + } + c->addr_iter = c->addr_first; + c->state = BIO_CONN_S_CREATE_SOCKET; + break; + + case BIO_CONN_S_CREATE_SOCKET: + ret = BIO_socket(BIO_ADDRINFO_family(c->addr_iter), + BIO_ADDRINFO_socktype(c->addr_iter), + BIO_ADDRINFO_protocol(c->addr_iter), 0); + if (ret == (int)INVALID_SOCKET) { + SYSerr(SYS_F_SOCKET, get_last_socket_error()); + ERR_add_error_data(4, + "hostname=", c->param_hostname, + " service=", c->param_service); + BIOerr(BIO_F_CONN_STATE, BIO_R_UNABLE_TO_CREATE_SOCKET); + goto exit_loop; + } + b->num = ret; + c->state = BIO_CONN_S_CONNECT; + break; + + case BIO_CONN_S_CONNECT: + BIO_clear_retry_flags(b); + ret = BIO_connect(b->num, BIO_ADDRINFO_address(c->addr_iter), + BIO_SOCK_KEEPALIVE | c->connect_mode); + b->retry_reason = 0; + if (ret == 0) { + if (BIO_sock_should_retry(ret)) { + BIO_set_retry_special(b); + c->state = BIO_CONN_S_BLOCKED_CONNECT; + b->retry_reason = BIO_RR_CONNECT; + ERR_clear_error(); + } else if ((c->addr_iter = BIO_ADDRINFO_next(c->addr_iter)) + != NULL) { + /* + * if there are more addresses to try, do that first + */ + BIO_closesocket(b->num); + c->state = BIO_CONN_S_CREATE_SOCKET; + ERR_clear_error(); + break; + } else { + SYSerr(SYS_F_CONNECT, get_last_socket_error()); + ERR_add_error_data(4, + "hostname=", c->param_hostname, + " service=", c->param_service); + c->state = BIO_CONN_S_CONNECT_ERROR; + break; + } + goto exit_loop; + } else { + c->state = BIO_CONN_S_OK; + } + break; + + case BIO_CONN_S_BLOCKED_CONNECT: + i = BIO_sock_error(b->num); + if (i) { + BIO_clear_retry_flags(b); + SYSerr(SYS_F_CONNECT, i); + ERR_add_error_data(4, + "hostname=", c->param_hostname, + " service=", c->param_service); + BIOerr(BIO_F_CONN_STATE, BIO_R_NBIO_CONNECT_ERROR); + ret = 0; + goto exit_loop; + } else + c->state = BIO_CONN_S_OK; + break; + + case BIO_CONN_S_CONNECT_ERROR: + BIOerr(BIO_F_CONN_STATE, BIO_R_CONNECT_ERROR); + ret = 0; + goto exit_loop; + + case BIO_CONN_S_OK: + ret = 1; + goto exit_loop; + default: + /* abort(); */ + goto exit_loop; + } + + if (cb != NULL) { + if ((ret = cb((BIO *)b, c->state, ret)) == 0) + goto end; + } + } + + /* Loop does not exit */ + exit_loop: + if (cb != NULL) + ret = cb((BIO *)b, c->state, ret); + end: + return ret; +} + +BIO_CONNECT *BIO_CONNECT_new(void) +{ + BIO_CONNECT *ret; + + if ((ret = OPENSSL_zalloc(sizeof(*ret))) == NULL) { + BIOerr(BIO_F_BIO_CONNECT_NEW, ERR_R_MALLOC_FAILURE); + return NULL; + } + ret->state = BIO_CONN_S_BEFORE; + ret->connect_family = BIO_FAMILY_IPANY; + return ret; +} + +void BIO_CONNECT_free(BIO_CONNECT *a) +{ + if (a == NULL) + return; + OPENSSL_free(a->param_hostname); + OPENSSL_free(a->param_service); + BIO_ADDRINFO_free(a->addr_first); + OPENSSL_free(a); +} + +const BIO_METHOD *BIO_s_connect(void) +{ + return &methods_connectp; +} + +static int conn_new(BIO *bi) +{ + bi->init = 0; + bi->num = (int)INVALID_SOCKET; + bi->flags = 0; + if ((bi->ptr = (char *)BIO_CONNECT_new()) == NULL) + return 0; + else + return 1; +} + +static void conn_close_socket(BIO *bio) +{ + BIO_CONNECT *c; + + c = (BIO_CONNECT *)bio->ptr; + if (bio->num != (int)INVALID_SOCKET) { + /* Only do a shutdown if things were established */ + if (c->state == BIO_CONN_S_OK) + shutdown(bio->num, 2); + BIO_closesocket(bio->num); + bio->num = (int)INVALID_SOCKET; + } +} + +static int conn_free(BIO *a) +{ + BIO_CONNECT *data; + + if (a == NULL) + return 0; + data = (BIO_CONNECT *)a->ptr; + + if (a->shutdown) { + conn_close_socket(a); + BIO_CONNECT_free(data); + a->ptr = NULL; + a->flags = 0; + a->init = 0; + } + return 1; +} + +static int conn_read(BIO *b, char *out, int outl) +{ + int ret = 0; + BIO_CONNECT *data; + + data = (BIO_CONNECT *)b->ptr; + if (data->state != BIO_CONN_S_OK) { + ret = conn_state(b, data); + if (ret <= 0) + return ret; + } + + if (out != NULL) { + clear_socket_error(); + ret = readsocket(b->num, out, outl); + BIO_clear_retry_flags(b); + if (ret <= 0) { + if (BIO_sock_should_retry(ret)) + BIO_set_retry_read(b); + else if (ret == 0) + b->flags |= BIO_FLAGS_IN_EOF; + } + } + return ret; +} + +static int conn_write(BIO *b, const char *in, int inl) +{ + int ret; + BIO_CONNECT *data; + + data = (BIO_CONNECT *)b->ptr; + if (data->state != BIO_CONN_S_OK) { + ret = conn_state(b, data); + if (ret <= 0) + return ret; + } + + clear_socket_error(); + ret = writesocket(b->num, in, inl); + BIO_clear_retry_flags(b); + if (ret <= 0) { + if (BIO_sock_should_retry(ret)) + BIO_set_retry_write(b); + } + return ret; +} + +static long conn_ctrl(BIO *b, int cmd, long num, void *ptr) +{ + BIO *dbio; + int *ip; + const char **pptr = NULL; + long ret = 1; + BIO_CONNECT *data; + + data = (BIO_CONNECT *)b->ptr; + + switch (cmd) { + case BIO_CTRL_RESET: + ret = 0; + data->state = BIO_CONN_S_BEFORE; + conn_close_socket(b); + BIO_ADDRINFO_free(data->addr_first); + data->addr_first = NULL; + b->flags = 0; + break; + case BIO_C_DO_STATE_MACHINE: + /* use this one to start the connection */ + if (data->state != BIO_CONN_S_OK) + ret = (long)conn_state(b, data); + else + ret = 1; + break; + case BIO_C_GET_CONNECT: + if (ptr != NULL) { + pptr = (const char **)ptr; + if (num == 0) { + *pptr = data->param_hostname; + } else if (num == 1) { + *pptr = data->param_service; + } else if (num == 2) { + *pptr = (const char *)BIO_ADDRINFO_address(data->addr_iter); + } else if (num == 3) { + switch (BIO_ADDRINFO_family(data->addr_iter)) { +# ifdef AF_INET6 + case AF_INET6: + ret = BIO_FAMILY_IPV6; + break; +# endif + case AF_INET: + ret = BIO_FAMILY_IPV4; + break; + case 0: + ret = data->connect_family; + break; + default: + ret = -1; + break; + } + } else { + ret = 0; + } + } else { + ret = 0; + } + break; + case BIO_C_SET_CONNECT: + if (ptr != NULL) { + b->init = 1; + if (num == 0) { + char *hold_service = data->param_service; + /* We affect the hostname regardless. However, the input + * string might contain a host:service spec, so we must + * parse it, which might or might not affect the service + */ + OPENSSL_free(data->param_hostname); + data->param_hostname = NULL; + ret = BIO_parse_hostserv(ptr, + &data->param_hostname, + &data->param_service, + BIO_PARSE_PRIO_HOST); + if (hold_service != data->param_service) + OPENSSL_free(hold_service); + } else if (num == 1) { + OPENSSL_free(data->param_service); + data->param_service = BUF_strdup(ptr); + } else if (num == 2) { + const BIO_ADDR *addr = (const BIO_ADDR *)ptr; + if (ret) { + data->param_hostname = BIO_ADDR_hostname_string(addr, 1); + data->param_service = BIO_ADDR_service_string(addr, 1); + BIO_ADDRINFO_free(data->addr_first); + data->addr_first = NULL; + data->addr_iter = NULL; + } + } else if (num == 3) { + data->connect_family = *(int *)ptr; + } else { + ret = 0; + } + } + break; + case BIO_C_SET_NBIO: + if (num != 0) + data->connect_mode |= BIO_SOCK_NONBLOCK; + else + data->connect_mode &= ~BIO_SOCK_NONBLOCK; + break; + case BIO_C_SET_CONNECT_MODE: + data->connect_mode = (int)num; + break; + case BIO_C_GET_FD: + if (b->init) { + ip = (int *)ptr; + if (ip != NULL) + *ip = b->num; + ret = b->num; + } else + ret = -1; + break; + case BIO_CTRL_GET_CLOSE: + ret = b->shutdown; + break; + case BIO_CTRL_SET_CLOSE: + b->shutdown = (int)num; + break; + case BIO_CTRL_PENDING: + case BIO_CTRL_WPENDING: + ret = 0; + break; + case BIO_CTRL_FLUSH: + break; + case BIO_CTRL_DUP: + { + dbio = (BIO *)ptr; + if (data->param_hostname) + BIO_set_conn_hostname(dbio, data->param_hostname); + if (data->param_service) + BIO_set_conn_port(dbio, data->param_service); + BIO_set_conn_ip_family(dbio, data->connect_family); + BIO_set_conn_mode(dbio, data->connect_mode); + /* + * FIXME: the cast of the function seems unlikely to be a good + * idea + */ + (void)BIO_set_info_callback(dbio, data->info_callback); + } + break; + case BIO_CTRL_SET_CALLBACK: + ret = 0; /* use callback ctrl */ + break; + case BIO_CTRL_GET_CALLBACK: + { + BIO_info_cb **fptr; + + fptr = (BIO_info_cb **)ptr; + *fptr = data->info_callback; + } + break; + case BIO_CTRL_EOF: + ret = (b->flags & BIO_FLAGS_IN_EOF) != 0 ? 1 : 0; + break; + default: + ret = 0; + break; + } + return ret; +} + +static long conn_callback_ctrl(BIO *b, int cmd, BIO_info_cb *fp) +{ + long ret = 1; + BIO_CONNECT *data; + + data = (BIO_CONNECT *)b->ptr; + + switch (cmd) { + case BIO_CTRL_SET_CALLBACK: + { + data->info_callback = fp; + } + break; + default: + ret = 0; + break; + } + return ret; +} + +static int conn_puts(BIO *bp, const char *str) +{ + int n, ret; + + n = strlen(str); + ret = conn_write(bp, str, n); + return ret; +} + +BIO *BIO_new_connect(const char *str) +{ + BIO *ret; + + ret = BIO_new(BIO_s_connect()); + if (ret == NULL) + return NULL; + if (BIO_set_conn_hostname(ret, str)) + return ret; + BIO_free(ret); + return NULL; +} + +#endif diff --git a/roms/edk2/CryptoPkg/Library/OpensslLib/openssl/crypto/bio/bss_dgram.c b/roms/edk2/CryptoPkg/Library/OpensslLib/openssl/crypto/bio/bss_dgram.c new file mode 100644 index 000000000..942fd8b51 --- /dev/null +++ b/roms/edk2/CryptoPkg/Library/OpensslLib/openssl/crypto/bio/bss_dgram.c @@ -0,0 +1,1925 @@ +/* + * Copyright 2005-2019 The OpenSSL Project Authors. All Rights Reserved. + * + * Licensed under the OpenSSL license (the "License"). You may not use + * this file except in compliance with the License. You can obtain a copy + * in the file LICENSE in the source distribution or at + * https://www.openssl.org/source/license.html + */ + +#include <stdio.h> +#include <errno.h> + +#include "bio_local.h" +#ifndef OPENSSL_NO_DGRAM + +# ifndef OPENSSL_NO_SCTP +# include <netinet/sctp.h> +# include <fcntl.h> +# define OPENSSL_SCTP_DATA_CHUNK_TYPE 0x00 +# define OPENSSL_SCTP_FORWARD_CUM_TSN_CHUNK_TYPE 0xc0 +# endif + +# if defined(OPENSSL_SYS_LINUX) && !defined(IP_MTU) +# define IP_MTU 14 /* linux is lame */ +# endif + +# if OPENSSL_USE_IPV6 && !defined(IPPROTO_IPV6) +# define IPPROTO_IPV6 41 /* windows is lame */ +# endif + +# if defined(__FreeBSD__) && defined(IN6_IS_ADDR_V4MAPPED) +/* Standard definition causes type-punning problems. */ +# undef IN6_IS_ADDR_V4MAPPED +# define s6_addr32 __u6_addr.__u6_addr32 +# define IN6_IS_ADDR_V4MAPPED(a) \ + (((a)->s6_addr32[0] == 0) && \ + ((a)->s6_addr32[1] == 0) && \ + ((a)->s6_addr32[2] == htonl(0x0000ffff))) +# endif + +static int dgram_write(BIO *h, const char *buf, int num); +static int dgram_read(BIO *h, char *buf, int size); +static int dgram_puts(BIO *h, const char *str); +static long dgram_ctrl(BIO *h, int cmd, long arg1, void *arg2); +static int dgram_new(BIO *h); +static int dgram_free(BIO *data); +static int dgram_clear(BIO *bio); + +# ifndef OPENSSL_NO_SCTP +static int dgram_sctp_write(BIO *h, const char *buf, int num); +static int dgram_sctp_read(BIO *h, char *buf, int size); +static int dgram_sctp_puts(BIO *h, const char *str); +static long dgram_sctp_ctrl(BIO *h, int cmd, long arg1, void *arg2); +static int dgram_sctp_new(BIO *h); +static int dgram_sctp_free(BIO *data); +# ifdef SCTP_AUTHENTICATION_EVENT +static void dgram_sctp_handle_auth_free_key_event(BIO *b, union sctp_notification + *snp); +# endif +# endif + +static int BIO_dgram_should_retry(int s); + +static void get_current_time(struct timeval *t); + +static const BIO_METHOD methods_dgramp = { + BIO_TYPE_DGRAM, + "datagram socket", + /* TODO: Convert to new style write function */ + bwrite_conv, + dgram_write, + /* TODO: Convert to new style read function */ + bread_conv, + dgram_read, + dgram_puts, + NULL, /* dgram_gets, */ + dgram_ctrl, + dgram_new, + dgram_free, + NULL, /* dgram_callback_ctrl */ +}; + +# ifndef OPENSSL_NO_SCTP +static const BIO_METHOD methods_dgramp_sctp = { + BIO_TYPE_DGRAM_SCTP, + "datagram sctp socket", + /* TODO: Convert to new style write function */ + bwrite_conv, + dgram_sctp_write, + /* TODO: Convert to new style write function */ + bread_conv, + dgram_sctp_read, + dgram_sctp_puts, + NULL, /* dgram_gets, */ + dgram_sctp_ctrl, + dgram_sctp_new, + dgram_sctp_free, + NULL, /* dgram_callback_ctrl */ +}; +# endif + +typedef struct bio_dgram_data_st { + BIO_ADDR peer; + unsigned int connected; + unsigned int _errno; + unsigned int mtu; + struct timeval next_timeout; + struct timeval socket_timeout; + unsigned int peekmode; +} bio_dgram_data; + +# ifndef OPENSSL_NO_SCTP +typedef struct bio_dgram_sctp_save_message_st { + BIO *bio; + char *data; + int length; +} bio_dgram_sctp_save_message; + +typedef struct bio_dgram_sctp_data_st { + BIO_ADDR peer; + unsigned int connected; + unsigned int _errno; + unsigned int mtu; + struct bio_dgram_sctp_sndinfo sndinfo; + struct bio_dgram_sctp_rcvinfo rcvinfo; + struct bio_dgram_sctp_prinfo prinfo; + void (*handle_notifications) (BIO *bio, void *context, void *buf); + void *notification_context; + int in_handshake; + int ccs_rcvd; + int ccs_sent; + int save_shutdown; + int peer_auth_tested; +} bio_dgram_sctp_data; +# endif + +const BIO_METHOD *BIO_s_datagram(void) +{ + return &methods_dgramp; +} + +BIO *BIO_new_dgram(int fd, int close_flag) +{ + BIO *ret; + + ret = BIO_new(BIO_s_datagram()); + if (ret == NULL) + return NULL; + BIO_set_fd(ret, fd, close_flag); + return ret; +} + +static int dgram_new(BIO *bi) +{ + bio_dgram_data *data = OPENSSL_zalloc(sizeof(*data)); + + if (data == NULL) + return 0; + bi->ptr = data; + return 1; +} + +static int dgram_free(BIO *a) +{ + bio_dgram_data *data; + + if (a == NULL) + return 0; + if (!dgram_clear(a)) + return 0; + + data = (bio_dgram_data *)a->ptr; + OPENSSL_free(data); + + return 1; +} + +static int dgram_clear(BIO *a) +{ + if (a == NULL) + return 0; + if (a->shutdown) { + if (a->init) { + BIO_closesocket(a->num); + } + a->init = 0; + a->flags = 0; + } + return 1; +} + +static void dgram_adjust_rcv_timeout(BIO *b) +{ +# if defined(SO_RCVTIMEO) + bio_dgram_data *data = (bio_dgram_data *)b->ptr; + union { + size_t s; + int i; + } sz = { + 0 + }; + + /* Is a timer active? */ + if (data->next_timeout.tv_sec > 0 || data->next_timeout.tv_usec > 0) { + struct timeval timenow, timeleft; + + /* Read current socket timeout */ +# ifdef OPENSSL_SYS_WINDOWS + int timeout; + + sz.i = sizeof(timeout); + if (getsockopt(b->num, SOL_SOCKET, SO_RCVTIMEO, + (void *)&timeout, &sz.i) < 0) { + perror("getsockopt"); + } else { + data->socket_timeout.tv_sec = timeout / 1000; + data->socket_timeout.tv_usec = (timeout % 1000) * 1000; + } +# else + sz.i = sizeof(data->socket_timeout); + if (getsockopt(b->num, SOL_SOCKET, SO_RCVTIMEO, + &(data->socket_timeout), (void *)&sz) < 0) { + perror("getsockopt"); + } else if (sizeof(sz.s) != sizeof(sz.i) && sz.i == 0) + OPENSSL_assert(sz.s <= sizeof(data->socket_timeout)); +# endif + + /* Get current time */ + get_current_time(&timenow); + + /* Calculate time left until timer expires */ + memcpy(&timeleft, &(data->next_timeout), sizeof(struct timeval)); + if (timeleft.tv_usec < timenow.tv_usec) { + timeleft.tv_usec = 1000000 - timenow.tv_usec + timeleft.tv_usec; + timeleft.tv_sec--; + } else { + timeleft.tv_usec -= timenow.tv_usec; + } + if (timeleft.tv_sec < timenow.tv_sec) { + timeleft.tv_sec = 0; + timeleft.tv_usec = 1; + } else { + timeleft.tv_sec -= timenow.tv_sec; + } + + /* + * Adjust socket timeout if next handshake message timer will expire + * earlier. + */ + if ((data->socket_timeout.tv_sec == 0 + && data->socket_timeout.tv_usec == 0) + || (data->socket_timeout.tv_sec > timeleft.tv_sec) + || (data->socket_timeout.tv_sec == timeleft.tv_sec + && data->socket_timeout.tv_usec >= timeleft.tv_usec)) { +# ifdef OPENSSL_SYS_WINDOWS + timeout = timeleft.tv_sec * 1000 + timeleft.tv_usec / 1000; + if (setsockopt(b->num, SOL_SOCKET, SO_RCVTIMEO, + (void *)&timeout, sizeof(timeout)) < 0) { + perror("setsockopt"); + } +# else + if (setsockopt(b->num, SOL_SOCKET, SO_RCVTIMEO, &timeleft, + sizeof(struct timeval)) < 0) { + perror("setsockopt"); + } +# endif + } + } +# endif +} + +static void dgram_reset_rcv_timeout(BIO *b) +{ +# if defined(SO_RCVTIMEO) + bio_dgram_data *data = (bio_dgram_data *)b->ptr; + + /* Is a timer active? */ + if (data->next_timeout.tv_sec > 0 || data->next_timeout.tv_usec > 0) { +# ifdef OPENSSL_SYS_WINDOWS + int timeout = data->socket_timeout.tv_sec * 1000 + + data->socket_timeout.tv_usec / 1000; + if (setsockopt(b->num, SOL_SOCKET, SO_RCVTIMEO, + (void *)&timeout, sizeof(timeout)) < 0) { + perror("setsockopt"); + } +# else + if (setsockopt + (b->num, SOL_SOCKET, SO_RCVTIMEO, &(data->socket_timeout), + sizeof(struct timeval)) < 0) { + perror("setsockopt"); + } +# endif + } +# endif +} + +static int dgram_read(BIO *b, char *out, int outl) +{ + int ret = 0; + bio_dgram_data *data = (bio_dgram_data *)b->ptr; + int flags = 0; + + BIO_ADDR peer; + socklen_t len = sizeof(peer); + + if (out != NULL) { + clear_socket_error(); + memset(&peer, 0, sizeof(peer)); + dgram_adjust_rcv_timeout(b); + if (data->peekmode) + flags = MSG_PEEK; + ret = recvfrom(b->num, out, outl, flags, + BIO_ADDR_sockaddr_noconst(&peer), &len); + + if (!data->connected && ret >= 0) + BIO_ctrl(b, BIO_CTRL_DGRAM_SET_PEER, 0, &peer); + + BIO_clear_retry_flags(b); + if (ret < 0) { + if (BIO_dgram_should_retry(ret)) { + BIO_set_retry_read(b); + data->_errno = get_last_socket_error(); + } + } + + dgram_reset_rcv_timeout(b); + } + return ret; +} + +static int dgram_write(BIO *b, const char *in, int inl) +{ + int ret; + bio_dgram_data *data = (bio_dgram_data *)b->ptr; + clear_socket_error(); + + if (data->connected) + ret = writesocket(b->num, in, inl); + else { + int peerlen = BIO_ADDR_sockaddr_size(&data->peer); + + ret = sendto(b->num, in, inl, 0, + BIO_ADDR_sockaddr(&data->peer), peerlen); + } + + BIO_clear_retry_flags(b); + if (ret <= 0) { + if (BIO_dgram_should_retry(ret)) { + BIO_set_retry_write(b); + data->_errno = get_last_socket_error(); + } + } + return ret; +} + +static long dgram_get_mtu_overhead(bio_dgram_data *data) +{ + long ret; + + switch (BIO_ADDR_family(&data->peer)) { + case AF_INET: + /* + * Assume this is UDP - 20 bytes for IP, 8 bytes for UDP + */ + ret = 28; + break; +# if OPENSSL_USE_IPV6 + case AF_INET6: + { +# ifdef IN6_IS_ADDR_V4MAPPED + struct in6_addr tmp_addr; + if (BIO_ADDR_rawaddress(&data->peer, &tmp_addr, NULL) + && IN6_IS_ADDR_V4MAPPED(&tmp_addr)) + /* + * Assume this is UDP - 20 bytes for IP, 8 bytes for UDP + */ + ret = 28; + else +# endif + /* + * Assume this is UDP - 40 bytes for IP, 8 bytes for UDP + */ + ret = 48; + } + break; +# endif + default: + /* We don't know. Go with the historical default */ + ret = 28; + break; + } + return ret; +} + +static long dgram_ctrl(BIO *b, int cmd, long num, void *ptr) +{ + long ret = 1; + int *ip; + bio_dgram_data *data = NULL; + int sockopt_val = 0; + int d_errno; +# if defined(OPENSSL_SYS_LINUX) && (defined(IP_MTU_DISCOVER) || defined(IP_MTU)) + socklen_t sockopt_len; /* assume that system supporting IP_MTU is + * modern enough to define socklen_t */ + socklen_t addr_len; + BIO_ADDR addr; +# endif + + data = (bio_dgram_data *)b->ptr; + + switch (cmd) { + case BIO_CTRL_RESET: + num = 0; + ret = 0; + break; + case BIO_CTRL_INFO: + ret = 0; + break; + case BIO_C_SET_FD: + dgram_clear(b); + b->num = *((int *)ptr); + b->shutdown = (int)num; + b->init = 1; + break; + case BIO_C_GET_FD: + if (b->init) { + ip = (int *)ptr; + if (ip != NULL) + *ip = b->num; + ret = b->num; + } else + ret = -1; + break; + case BIO_CTRL_GET_CLOSE: + ret = b->shutdown; + break; + case BIO_CTRL_SET_CLOSE: + b->shutdown = (int)num; + break; + case BIO_CTRL_PENDING: + case BIO_CTRL_WPENDING: + ret = 0; + break; + case BIO_CTRL_DUP: + case BIO_CTRL_FLUSH: + ret = 1; + break; + case BIO_CTRL_DGRAM_CONNECT: + BIO_ADDR_make(&data->peer, BIO_ADDR_sockaddr((BIO_ADDR *)ptr)); + break; + /* (Linux)kernel sets DF bit on outgoing IP packets */ + case BIO_CTRL_DGRAM_MTU_DISCOVER: +# if defined(OPENSSL_SYS_LINUX) && defined(IP_MTU_DISCOVER) && defined(IP_PMTUDISC_DO) + addr_len = (socklen_t) sizeof(addr); + memset(&addr, 0, sizeof(addr)); + if (getsockname(b->num, &addr.sa, &addr_len) < 0) { + ret = 0; + break; + } + switch (addr.sa.sa_family) { + case AF_INET: + sockopt_val = IP_PMTUDISC_DO; + if ((ret = setsockopt(b->num, IPPROTO_IP, IP_MTU_DISCOVER, + &sockopt_val, sizeof(sockopt_val))) < 0) + perror("setsockopt"); + break; +# if OPENSSL_USE_IPV6 && defined(IPV6_MTU_DISCOVER) && defined(IPV6_PMTUDISC_DO) + case AF_INET6: + sockopt_val = IPV6_PMTUDISC_DO; + if ((ret = setsockopt(b->num, IPPROTO_IPV6, IPV6_MTU_DISCOVER, + &sockopt_val, sizeof(sockopt_val))) < 0) + perror("setsockopt"); + break; +# endif + default: + ret = -1; + break; + } +# else + ret = -1; +# endif + break; + case BIO_CTRL_DGRAM_QUERY_MTU: +# if defined(OPENSSL_SYS_LINUX) && defined(IP_MTU) + addr_len = (socklen_t) sizeof(addr); + memset(&addr, 0, sizeof(addr)); + if (getsockname(b->num, &addr.sa, &addr_len) < 0) { + ret = 0; + break; + } + sockopt_len = sizeof(sockopt_val); + switch (addr.sa.sa_family) { + case AF_INET: + if ((ret = + getsockopt(b->num, IPPROTO_IP, IP_MTU, (void *)&sockopt_val, + &sockopt_len)) < 0 || sockopt_val < 0) { + ret = 0; + } else { + /* + * we assume that the transport protocol is UDP and no IP + * options are used. + */ + data->mtu = sockopt_val - 8 - 20; + ret = data->mtu; + } + break; +# if OPENSSL_USE_IPV6 && defined(IPV6_MTU) + case AF_INET6: + if ((ret = + getsockopt(b->num, IPPROTO_IPV6, IPV6_MTU, + (void *)&sockopt_val, &sockopt_len)) < 0 + || sockopt_val < 0) { + ret = 0; + } else { + /* + * we assume that the transport protocol is UDP and no IPV6 + * options are used. + */ + data->mtu = sockopt_val - 8 - 40; + ret = data->mtu; + } + break; +# endif + default: + ret = 0; + break; + } +# else + ret = 0; +# endif + break; + case BIO_CTRL_DGRAM_GET_FALLBACK_MTU: + ret = -dgram_get_mtu_overhead(data); + switch (BIO_ADDR_family(&data->peer)) { + case AF_INET: + ret += 576; + break; +# if OPENSSL_USE_IPV6 + case AF_INET6: + { +# ifdef IN6_IS_ADDR_V4MAPPED + struct in6_addr tmp_addr; + if (BIO_ADDR_rawaddress(&data->peer, &tmp_addr, NULL) + && IN6_IS_ADDR_V4MAPPED(&tmp_addr)) + ret += 576; + else +# endif + ret += 1280; + } + break; +# endif + default: + ret += 576; + break; + } + break; + case BIO_CTRL_DGRAM_GET_MTU: + return data->mtu; + case BIO_CTRL_DGRAM_SET_MTU: + data->mtu = num; + ret = num; + break; + case BIO_CTRL_DGRAM_SET_CONNECTED: + if (ptr != NULL) { + data->connected = 1; + BIO_ADDR_make(&data->peer, BIO_ADDR_sockaddr((BIO_ADDR *)ptr)); + } else { + data->connected = 0; + memset(&data->peer, 0, sizeof(data->peer)); + } + break; + case BIO_CTRL_DGRAM_GET_PEER: + ret = BIO_ADDR_sockaddr_size(&data->peer); + /* FIXME: if num < ret, we will only return part of an address. + That should bee an error, no? */ + if (num == 0 || num > ret) + num = ret; + memcpy(ptr, &data->peer, (ret = num)); + break; + case BIO_CTRL_DGRAM_SET_PEER: + BIO_ADDR_make(&data->peer, BIO_ADDR_sockaddr((BIO_ADDR *)ptr)); + break; + case BIO_CTRL_DGRAM_SET_NEXT_TIMEOUT: + memcpy(&(data->next_timeout), ptr, sizeof(struct timeval)); + break; +# if defined(SO_RCVTIMEO) + case BIO_CTRL_DGRAM_SET_RECV_TIMEOUT: +# ifdef OPENSSL_SYS_WINDOWS + { + struct timeval *tv = (struct timeval *)ptr; + int timeout = tv->tv_sec * 1000 + tv->tv_usec / 1000; + if (setsockopt(b->num, SOL_SOCKET, SO_RCVTIMEO, + (void *)&timeout, sizeof(timeout)) < 0) { + perror("setsockopt"); + ret = -1; + } + } +# else + if (setsockopt(b->num, SOL_SOCKET, SO_RCVTIMEO, ptr, + sizeof(struct timeval)) < 0) { + perror("setsockopt"); + ret = -1; + } +# endif + break; + case BIO_CTRL_DGRAM_GET_RECV_TIMEOUT: + { + union { + size_t s; + int i; + } sz = { + 0 + }; +# ifdef OPENSSL_SYS_WINDOWS + int timeout; + struct timeval *tv = (struct timeval *)ptr; + + sz.i = sizeof(timeout); + if (getsockopt(b->num, SOL_SOCKET, SO_RCVTIMEO, + (void *)&timeout, &sz.i) < 0) { + perror("getsockopt"); + ret = -1; + } else { + tv->tv_sec = timeout / 1000; + tv->tv_usec = (timeout % 1000) * 1000; + ret = sizeof(*tv); + } +# else + sz.i = sizeof(struct timeval); + if (getsockopt(b->num, SOL_SOCKET, SO_RCVTIMEO, + ptr, (void *)&sz) < 0) { + perror("getsockopt"); + ret = -1; + } else if (sizeof(sz.s) != sizeof(sz.i) && sz.i == 0) { + OPENSSL_assert(sz.s <= sizeof(struct timeval)); + ret = (int)sz.s; + } else + ret = sz.i; +# endif + } + break; +# endif +# if defined(SO_SNDTIMEO) + case BIO_CTRL_DGRAM_SET_SEND_TIMEOUT: +# ifdef OPENSSL_SYS_WINDOWS + { + struct timeval *tv = (struct timeval *)ptr; + int timeout = tv->tv_sec * 1000 + tv->tv_usec / 1000; + if (setsockopt(b->num, SOL_SOCKET, SO_SNDTIMEO, + (void *)&timeout, sizeof(timeout)) < 0) { + perror("setsockopt"); + ret = -1; + } + } +# else + if (setsockopt(b->num, SOL_SOCKET, SO_SNDTIMEO, ptr, + sizeof(struct timeval)) < 0) { + perror("setsockopt"); + ret = -1; + } +# endif + break; + case BIO_CTRL_DGRAM_GET_SEND_TIMEOUT: + { + union { + size_t s; + int i; + } sz = { + 0 + }; +# ifdef OPENSSL_SYS_WINDOWS + int timeout; + struct timeval *tv = (struct timeval *)ptr; + + sz.i = sizeof(timeout); + if (getsockopt(b->num, SOL_SOCKET, SO_SNDTIMEO, + (void *)&timeout, &sz.i) < 0) { + perror("getsockopt"); + ret = -1; + } else { + tv->tv_sec = timeout / 1000; + tv->tv_usec = (timeout % 1000) * 1000; + ret = sizeof(*tv); + } +# else + sz.i = sizeof(struct timeval); + if (getsockopt(b->num, SOL_SOCKET, SO_SNDTIMEO, + ptr, (void *)&sz) < 0) { + perror("getsockopt"); + ret = -1; + } else if (sizeof(sz.s) != sizeof(sz.i) && sz.i == 0) { + OPENSSL_assert(sz.s <= sizeof(struct timeval)); + ret = (int)sz.s; + } else + ret = sz.i; +# endif + } + break; +# endif + case BIO_CTRL_DGRAM_GET_SEND_TIMER_EXP: + /* fall-through */ + case BIO_CTRL_DGRAM_GET_RECV_TIMER_EXP: +# ifdef OPENSSL_SYS_WINDOWS + d_errno = (data->_errno == WSAETIMEDOUT); +# else + d_errno = (data->_errno == EAGAIN); +# endif + if (d_errno) { + ret = 1; + data->_errno = 0; + } else + ret = 0; + break; +# ifdef EMSGSIZE + case BIO_CTRL_DGRAM_MTU_EXCEEDED: + if (data->_errno == EMSGSIZE) { + ret = 1; + data->_errno = 0; + } else + ret = 0; + break; +# endif + case BIO_CTRL_DGRAM_SET_DONT_FRAG: + sockopt_val = num ? 1 : 0; + + switch (data->peer.sa.sa_family) { + case AF_INET: +# if defined(IP_DONTFRAG) + if ((ret = setsockopt(b->num, IPPROTO_IP, IP_DONTFRAG, + &sockopt_val, sizeof(sockopt_val))) < 0) { + perror("setsockopt"); + ret = -1; + } +# elif defined(OPENSSL_SYS_LINUX) && defined(IP_MTU_DISCOVER) && defined (IP_PMTUDISC_PROBE) + if ((sockopt_val = num ? IP_PMTUDISC_PROBE : IP_PMTUDISC_DONT), + (ret = setsockopt(b->num, IPPROTO_IP, IP_MTU_DISCOVER, + &sockopt_val, sizeof(sockopt_val))) < 0) { + perror("setsockopt"); + ret = -1; + } +# elif defined(OPENSSL_SYS_WINDOWS) && defined(IP_DONTFRAGMENT) + if ((ret = setsockopt(b->num, IPPROTO_IP, IP_DONTFRAGMENT, + (const char *)&sockopt_val, + sizeof(sockopt_val))) < 0) { + perror("setsockopt"); + ret = -1; + } +# else + ret = -1; +# endif + break; +# if OPENSSL_USE_IPV6 + case AF_INET6: +# if defined(IPV6_DONTFRAG) + if ((ret = setsockopt(b->num, IPPROTO_IPV6, IPV6_DONTFRAG, + (const void *)&sockopt_val, + sizeof(sockopt_val))) < 0) { + perror("setsockopt"); + ret = -1; + } +# elif defined(OPENSSL_SYS_LINUX) && defined(IPV6_MTUDISCOVER) + if ((sockopt_val = num ? IP_PMTUDISC_PROBE : IP_PMTUDISC_DONT), + (ret = setsockopt(b->num, IPPROTO_IPV6, IPV6_MTU_DISCOVER, + &sockopt_val, sizeof(sockopt_val))) < 0) { + perror("setsockopt"); + ret = -1; + } +# else + ret = -1; +# endif + break; +# endif + default: + ret = -1; + break; + } + break; + case BIO_CTRL_DGRAM_GET_MTU_OVERHEAD: + ret = dgram_get_mtu_overhead(data); + break; + + /* + * BIO_CTRL_DGRAM_SCTP_SET_IN_HANDSHAKE is used here for compatibility + * reasons. When BIO_CTRL_DGRAM_SET_PEEK_MODE was first defined its value + * was incorrectly clashing with BIO_CTRL_DGRAM_SCTP_SET_IN_HANDSHAKE. The + * value has been updated to a non-clashing value. However to preserve + * binary compatibility we now respond to both the old value and the new one + */ + case BIO_CTRL_DGRAM_SCTP_SET_IN_HANDSHAKE: + case BIO_CTRL_DGRAM_SET_PEEK_MODE: + data->peekmode = (unsigned int)num; + break; + default: + ret = 0; + break; + } + return ret; +} + +static int dgram_puts(BIO *bp, const char *str) +{ + int n, ret; + + n = strlen(str); + ret = dgram_write(bp, str, n); + return ret; +} + +# ifndef OPENSSL_NO_SCTP +const BIO_METHOD *BIO_s_datagram_sctp(void) +{ + return &methods_dgramp_sctp; +} + +BIO *BIO_new_dgram_sctp(int fd, int close_flag) +{ + BIO *bio; + int ret, optval = 20000; + int auth_data = 0, auth_forward = 0; + unsigned char *p; + struct sctp_authchunk auth; + struct sctp_authchunks *authchunks; + socklen_t sockopt_len; +# ifdef SCTP_AUTHENTICATION_EVENT +# ifdef SCTP_EVENT + struct sctp_event event; +# else + struct sctp_event_subscribe event; +# endif +# endif + + bio = BIO_new(BIO_s_datagram_sctp()); + if (bio == NULL) + return NULL; + BIO_set_fd(bio, fd, close_flag); + + /* Activate SCTP-AUTH for DATA and FORWARD-TSN chunks */ + auth.sauth_chunk = OPENSSL_SCTP_DATA_CHUNK_TYPE; + ret = + setsockopt(fd, IPPROTO_SCTP, SCTP_AUTH_CHUNK, &auth, + sizeof(struct sctp_authchunk)); + if (ret < 0) { + BIO_vfree(bio); + BIOerr(BIO_F_BIO_NEW_DGRAM_SCTP, ERR_R_SYS_LIB); + ERR_add_error_data(1, "Ensure SCTP AUTH chunks are enabled in kernel"); + return NULL; + } + auth.sauth_chunk = OPENSSL_SCTP_FORWARD_CUM_TSN_CHUNK_TYPE; + ret = + setsockopt(fd, IPPROTO_SCTP, SCTP_AUTH_CHUNK, &auth, + sizeof(struct sctp_authchunk)); + if (ret < 0) { + BIO_vfree(bio); + BIOerr(BIO_F_BIO_NEW_DGRAM_SCTP, ERR_R_SYS_LIB); + ERR_add_error_data(1, "Ensure SCTP AUTH chunks are enabled in kernel"); + return NULL; + } + + /* + * Test if activation was successful. When using accept(), SCTP-AUTH has + * to be activated for the listening socket already, otherwise the + * connected socket won't use it. Similarly with connect(): the socket + * prior to connection must be activated for SCTP-AUTH + */ + sockopt_len = (socklen_t) (sizeof(sctp_assoc_t) + 256 * sizeof(uint8_t)); + authchunks = OPENSSL_zalloc(sockopt_len); + if (authchunks == NULL) { + BIO_vfree(bio); + return NULL; + } + ret = getsockopt(fd, IPPROTO_SCTP, SCTP_LOCAL_AUTH_CHUNKS, authchunks, + &sockopt_len); + if (ret < 0) { + OPENSSL_free(authchunks); + BIO_vfree(bio); + return NULL; + } + + for (p = (unsigned char *)authchunks->gauth_chunks; + p < (unsigned char *)authchunks + sockopt_len; + p += sizeof(uint8_t)) { + if (*p == OPENSSL_SCTP_DATA_CHUNK_TYPE) + auth_data = 1; + if (*p == OPENSSL_SCTP_FORWARD_CUM_TSN_CHUNK_TYPE) + auth_forward = 1; + } + + OPENSSL_free(authchunks); + + if (!auth_data || !auth_forward) { + BIO_vfree(bio); + BIOerr(BIO_F_BIO_NEW_DGRAM_SCTP, ERR_R_SYS_LIB); + ERR_add_error_data(1, + "Ensure SCTP AUTH chunks are enabled on the " + "underlying socket"); + return NULL; + } + +# ifdef SCTP_AUTHENTICATION_EVENT +# ifdef SCTP_EVENT + memset(&event, 0, sizeof(event)); + event.se_assoc_id = 0; + event.se_type = SCTP_AUTHENTICATION_EVENT; + event.se_on = 1; + ret = + setsockopt(fd, IPPROTO_SCTP, SCTP_EVENT, &event, + sizeof(struct sctp_event)); + if (ret < 0) { + BIO_vfree(bio); + return NULL; + } +# else + sockopt_len = (socklen_t) sizeof(struct sctp_event_subscribe); + ret = getsockopt(fd, IPPROTO_SCTP, SCTP_EVENTS, &event, &sockopt_len); + if (ret < 0) { + BIO_vfree(bio); + return NULL; + } + + event.sctp_authentication_event = 1; + + ret = + setsockopt(fd, IPPROTO_SCTP, SCTP_EVENTS, &event, + sizeof(struct sctp_event_subscribe)); + if (ret < 0) { + BIO_vfree(bio); + return NULL; + } +# endif +# endif + + /* + * Disable partial delivery by setting the min size larger than the max + * record size of 2^14 + 2048 + 13 + */ + ret = + setsockopt(fd, IPPROTO_SCTP, SCTP_PARTIAL_DELIVERY_POINT, &optval, + sizeof(optval)); + if (ret < 0) { + BIO_vfree(bio); + return NULL; + } + + return bio; +} + +int BIO_dgram_is_sctp(BIO *bio) +{ + return (BIO_method_type(bio) == BIO_TYPE_DGRAM_SCTP); +} + +static int dgram_sctp_new(BIO *bi) +{ + bio_dgram_sctp_data *data = NULL; + + bi->init = 0; + bi->num = 0; + if ((data = OPENSSL_zalloc(sizeof(*data))) == NULL) { + BIOerr(BIO_F_DGRAM_SCTP_NEW, ERR_R_MALLOC_FAILURE); + return 0; + } +# ifdef SCTP_PR_SCTP_NONE + data->prinfo.pr_policy = SCTP_PR_SCTP_NONE; +# endif + bi->ptr = data; + + bi->flags = 0; + return 1; +} + +static int dgram_sctp_free(BIO *a) +{ + bio_dgram_sctp_data *data; + + if (a == NULL) + return 0; + if (!dgram_clear(a)) + return 0; + + data = (bio_dgram_sctp_data *) a->ptr; + if (data != NULL) + OPENSSL_free(data); + + return 1; +} + +# ifdef SCTP_AUTHENTICATION_EVENT +void dgram_sctp_handle_auth_free_key_event(BIO *b, + union sctp_notification *snp) +{ + int ret; + struct sctp_authkey_event *authkeyevent = &snp->sn_auth_event; + + if (authkeyevent->auth_indication == SCTP_AUTH_FREE_KEY) { + struct sctp_authkeyid authkeyid; + + /* delete key */ + authkeyid.scact_keynumber = authkeyevent->auth_keynumber; + ret = setsockopt(b->num, IPPROTO_SCTP, SCTP_AUTH_DELETE_KEY, + &authkeyid, sizeof(struct sctp_authkeyid)); + } +} +# endif + +static int dgram_sctp_read(BIO *b, char *out, int outl) +{ + int ret = 0, n = 0, i, optval; + socklen_t optlen; + bio_dgram_sctp_data *data = (bio_dgram_sctp_data *) b->ptr; + union sctp_notification *snp; + struct msghdr msg; + struct iovec iov; + struct cmsghdr *cmsg; + char cmsgbuf[512]; + + if (out != NULL) { + clear_socket_error(); + + do { + memset(&data->rcvinfo, 0, sizeof(data->rcvinfo)); + iov.iov_base = out; + iov.iov_len = outl; + msg.msg_name = NULL; + msg.msg_namelen = 0; + msg.msg_iov = &iov; + msg.msg_iovlen = 1; + msg.msg_control = cmsgbuf; + msg.msg_controllen = 512; + msg.msg_flags = 0; + n = recvmsg(b->num, &msg, 0); + + if (n <= 0) { + if (n < 0) + ret = n; + break; + } + + if (msg.msg_controllen > 0) { + for (cmsg = CMSG_FIRSTHDR(&msg); cmsg; + cmsg = CMSG_NXTHDR(&msg, cmsg)) { + if (cmsg->cmsg_level != IPPROTO_SCTP) + continue; +# ifdef SCTP_RCVINFO + if (cmsg->cmsg_type == SCTP_RCVINFO) { + struct sctp_rcvinfo *rcvinfo; + + rcvinfo = (struct sctp_rcvinfo *)CMSG_DATA(cmsg); + data->rcvinfo.rcv_sid = rcvinfo->rcv_sid; + data->rcvinfo.rcv_ssn = rcvinfo->rcv_ssn; + data->rcvinfo.rcv_flags = rcvinfo->rcv_flags; + data->rcvinfo.rcv_ppid = rcvinfo->rcv_ppid; + data->rcvinfo.rcv_tsn = rcvinfo->rcv_tsn; + data->rcvinfo.rcv_cumtsn = rcvinfo->rcv_cumtsn; + data->rcvinfo.rcv_context = rcvinfo->rcv_context; + } +# endif +# ifdef SCTP_SNDRCV + if (cmsg->cmsg_type == SCTP_SNDRCV) { + struct sctp_sndrcvinfo *sndrcvinfo; + + sndrcvinfo = + (struct sctp_sndrcvinfo *)CMSG_DATA(cmsg); + data->rcvinfo.rcv_sid = sndrcvinfo->sinfo_stream; + data->rcvinfo.rcv_ssn = sndrcvinfo->sinfo_ssn; + data->rcvinfo.rcv_flags = sndrcvinfo->sinfo_flags; + data->rcvinfo.rcv_ppid = sndrcvinfo->sinfo_ppid; + data->rcvinfo.rcv_tsn = sndrcvinfo->sinfo_tsn; + data->rcvinfo.rcv_cumtsn = sndrcvinfo->sinfo_cumtsn; + data->rcvinfo.rcv_context = sndrcvinfo->sinfo_context; + } +# endif + } + } + + if (msg.msg_flags & MSG_NOTIFICATION) { + snp = (union sctp_notification *)out; + if (snp->sn_header.sn_type == SCTP_SENDER_DRY_EVENT) { +# ifdef SCTP_EVENT + struct sctp_event event; +# else + struct sctp_event_subscribe event; + socklen_t eventsize; +# endif + + /* disable sender dry event */ +# ifdef SCTP_EVENT + memset(&event, 0, sizeof(event)); + event.se_assoc_id = 0; + event.se_type = SCTP_SENDER_DRY_EVENT; + event.se_on = 0; + i = setsockopt(b->num, IPPROTO_SCTP, SCTP_EVENT, &event, + sizeof(struct sctp_event)); + if (i < 0) { + ret = i; + break; + } +# else + eventsize = sizeof(struct sctp_event_subscribe); + i = getsockopt(b->num, IPPROTO_SCTP, SCTP_EVENTS, &event, + &eventsize); + if (i < 0) { + ret = i; + break; + } + + event.sctp_sender_dry_event = 0; + + i = setsockopt(b->num, IPPROTO_SCTP, SCTP_EVENTS, &event, + sizeof(struct sctp_event_subscribe)); + if (i < 0) { + ret = i; + break; + } +# endif + } +# ifdef SCTP_AUTHENTICATION_EVENT + if (snp->sn_header.sn_type == SCTP_AUTHENTICATION_EVENT) + dgram_sctp_handle_auth_free_key_event(b, snp); +# endif + + if (data->handle_notifications != NULL) + data->handle_notifications(b, data->notification_context, + (void *)out); + + memset(out, 0, outl); + } else + ret += n; + } + while ((msg.msg_flags & MSG_NOTIFICATION) && (msg.msg_flags & MSG_EOR) + && (ret < outl)); + + if (ret > 0 && !(msg.msg_flags & MSG_EOR)) { + /* Partial message read, this should never happen! */ + + /* + * The buffer was too small, this means the peer sent a message + * that was larger than allowed. + */ + if (ret == outl) + return -1; + + /* + * Test if socket buffer can handle max record size (2^14 + 2048 + * + 13) + */ + optlen = (socklen_t) sizeof(int); + ret = getsockopt(b->num, SOL_SOCKET, SO_RCVBUF, &optval, &optlen); + if (ret >= 0) + OPENSSL_assert(optval >= 18445); + + /* + * Test if SCTP doesn't partially deliver below max record size + * (2^14 + 2048 + 13) + */ + optlen = (socklen_t) sizeof(int); + ret = + getsockopt(b->num, IPPROTO_SCTP, SCTP_PARTIAL_DELIVERY_POINT, + &optval, &optlen); + if (ret >= 0) + OPENSSL_assert(optval >= 18445); + + /* + * Partially delivered notification??? Probably a bug.... + */ + OPENSSL_assert(!(msg.msg_flags & MSG_NOTIFICATION)); + + /* + * Everything seems ok till now, so it's most likely a message + * dropped by PR-SCTP. + */ + memset(out, 0, outl); + BIO_set_retry_read(b); + return -1; + } + + BIO_clear_retry_flags(b); + if (ret < 0) { + if (BIO_dgram_should_retry(ret)) { + BIO_set_retry_read(b); + data->_errno = get_last_socket_error(); + } + } + + /* Test if peer uses SCTP-AUTH before continuing */ + if (!data->peer_auth_tested) { + int ii, auth_data = 0, auth_forward = 0; + unsigned char *p; + struct sctp_authchunks *authchunks; + + optlen = + (socklen_t) (sizeof(sctp_assoc_t) + 256 * sizeof(uint8_t)); + authchunks = OPENSSL_malloc(optlen); + if (authchunks == NULL) { + BIOerr(BIO_F_DGRAM_SCTP_READ, ERR_R_MALLOC_FAILURE); + return -1; + } + memset(authchunks, 0, optlen); + ii = getsockopt(b->num, IPPROTO_SCTP, SCTP_PEER_AUTH_CHUNKS, + authchunks, &optlen); + + if (ii >= 0) + for (p = (unsigned char *)authchunks->gauth_chunks; + p < (unsigned char *)authchunks + optlen; + p += sizeof(uint8_t)) { + if (*p == OPENSSL_SCTP_DATA_CHUNK_TYPE) + auth_data = 1; + if (*p == OPENSSL_SCTP_FORWARD_CUM_TSN_CHUNK_TYPE) + auth_forward = 1; + } + + OPENSSL_free(authchunks); + + if (!auth_data || !auth_forward) { + BIOerr(BIO_F_DGRAM_SCTP_READ, BIO_R_CONNECT_ERROR); + return -1; + } + + data->peer_auth_tested = 1; + } + } + return ret; +} + +/* + * dgram_sctp_write - send message on SCTP socket + * @b: BIO to write to + * @in: data to send + * @inl: amount of bytes in @in to send + * + * Returns -1 on error or the sent amount of bytes on success + */ +static int dgram_sctp_write(BIO *b, const char *in, int inl) +{ + int ret; + bio_dgram_sctp_data *data = (bio_dgram_sctp_data *) b->ptr; + struct bio_dgram_sctp_sndinfo *sinfo = &(data->sndinfo); + struct bio_dgram_sctp_prinfo *pinfo = &(data->prinfo); + struct bio_dgram_sctp_sndinfo handshake_sinfo; + struct iovec iov[1]; + struct msghdr msg; + struct cmsghdr *cmsg; +# if defined(SCTP_SNDINFO) && defined(SCTP_PRINFO) + char cmsgbuf[CMSG_SPACE(sizeof(struct sctp_sndinfo)) + + CMSG_SPACE(sizeof(struct sctp_prinfo))]; + struct sctp_sndinfo *sndinfo; + struct sctp_prinfo *prinfo; +# else + char cmsgbuf[CMSG_SPACE(sizeof(struct sctp_sndrcvinfo))]; + struct sctp_sndrcvinfo *sndrcvinfo; +# endif + + clear_socket_error(); + + /* + * If we're send anything else than application data, disable all user + * parameters and flags. + */ + if (in[0] != 23) { + memset(&handshake_sinfo, 0, sizeof(handshake_sinfo)); +# ifdef SCTP_SACK_IMMEDIATELY + handshake_sinfo.snd_flags = SCTP_SACK_IMMEDIATELY; +# endif + sinfo = &handshake_sinfo; + } + + /* We can only send a shutdown alert if the socket is dry */ + if (data->save_shutdown) { + ret = BIO_dgram_sctp_wait_for_dry(b); + if (ret < 0) + return -1; + if (ret == 0) { + BIO_clear_retry_flags(b); + BIO_set_retry_write(b); + return -1; + } + } + + iov[0].iov_base = (char *)in; + iov[0].iov_len = inl; + msg.msg_name = NULL; + msg.msg_namelen = 0; + msg.msg_iov = iov; + msg.msg_iovlen = 1; + msg.msg_control = (caddr_t) cmsgbuf; + msg.msg_controllen = 0; + msg.msg_flags = 0; +# if defined(SCTP_SNDINFO) && defined(SCTP_PRINFO) + cmsg = (struct cmsghdr *)cmsgbuf; + cmsg->cmsg_level = IPPROTO_SCTP; + cmsg->cmsg_type = SCTP_SNDINFO; + cmsg->cmsg_len = CMSG_LEN(sizeof(struct sctp_sndinfo)); + sndinfo = (struct sctp_sndinfo *)CMSG_DATA(cmsg); + memset(sndinfo, 0, sizeof(*sndinfo)); + sndinfo->snd_sid = sinfo->snd_sid; + sndinfo->snd_flags = sinfo->snd_flags; + sndinfo->snd_ppid = sinfo->snd_ppid; + sndinfo->snd_context = sinfo->snd_context; + msg.msg_controllen += CMSG_SPACE(sizeof(struct sctp_sndinfo)); + + cmsg = + (struct cmsghdr *)&cmsgbuf[CMSG_SPACE(sizeof(struct sctp_sndinfo))]; + cmsg->cmsg_level = IPPROTO_SCTP; + cmsg->cmsg_type = SCTP_PRINFO; + cmsg->cmsg_len = CMSG_LEN(sizeof(struct sctp_prinfo)); + prinfo = (struct sctp_prinfo *)CMSG_DATA(cmsg); + memset(prinfo, 0, sizeof(*prinfo)); + prinfo->pr_policy = pinfo->pr_policy; + prinfo->pr_value = pinfo->pr_value; + msg.msg_controllen += CMSG_SPACE(sizeof(struct sctp_prinfo)); +# else + cmsg = (struct cmsghdr *)cmsgbuf; + cmsg->cmsg_level = IPPROTO_SCTP; + cmsg->cmsg_type = SCTP_SNDRCV; + cmsg->cmsg_len = CMSG_LEN(sizeof(struct sctp_sndrcvinfo)); + sndrcvinfo = (struct sctp_sndrcvinfo *)CMSG_DATA(cmsg); + memset(sndrcvinfo, 0, sizeof(*sndrcvinfo)); + sndrcvinfo->sinfo_stream = sinfo->snd_sid; + sndrcvinfo->sinfo_flags = sinfo->snd_flags; +# ifdef __FreeBSD__ + sndrcvinfo->sinfo_flags |= pinfo->pr_policy; +# endif + sndrcvinfo->sinfo_ppid = sinfo->snd_ppid; + sndrcvinfo->sinfo_context = sinfo->snd_context; + sndrcvinfo->sinfo_timetolive = pinfo->pr_value; + msg.msg_controllen += CMSG_SPACE(sizeof(struct sctp_sndrcvinfo)); +# endif + + ret = sendmsg(b->num, &msg, 0); + + BIO_clear_retry_flags(b); + if (ret <= 0) { + if (BIO_dgram_should_retry(ret)) { + BIO_set_retry_write(b); + data->_errno = get_last_socket_error(); + } + } + return ret; +} + +static long dgram_sctp_ctrl(BIO *b, int cmd, long num, void *ptr) +{ + long ret = 1; + bio_dgram_sctp_data *data = NULL; + socklen_t sockopt_len = 0; + struct sctp_authkeyid authkeyid; + struct sctp_authkey *authkey = NULL; + + data = (bio_dgram_sctp_data *) b->ptr; + + switch (cmd) { + case BIO_CTRL_DGRAM_QUERY_MTU: + /* + * Set to maximum (2^14) and ignore user input to enable transport + * protocol fragmentation. Returns always 2^14. + */ + data->mtu = 16384; + ret = data->mtu; + break; + case BIO_CTRL_DGRAM_SET_MTU: + /* + * Set to maximum (2^14) and ignore input to enable transport + * protocol fragmentation. Returns always 2^14. + */ + data->mtu = 16384; + ret = data->mtu; + break; + case BIO_CTRL_DGRAM_SET_CONNECTED: + case BIO_CTRL_DGRAM_CONNECT: + /* Returns always -1. */ + ret = -1; + break; + case BIO_CTRL_DGRAM_SET_NEXT_TIMEOUT: + /* + * SCTP doesn't need the DTLS timer Returns always 1. + */ + break; + case BIO_CTRL_DGRAM_GET_MTU_OVERHEAD: + /* + * We allow transport protocol fragmentation so this is irrelevant + */ + ret = 0; + break; + case BIO_CTRL_DGRAM_SCTP_SET_IN_HANDSHAKE: + if (num > 0) + data->in_handshake = 1; + else + data->in_handshake = 0; + + ret = + setsockopt(b->num, IPPROTO_SCTP, SCTP_NODELAY, + &data->in_handshake, sizeof(int)); + break; + case BIO_CTRL_DGRAM_SCTP_ADD_AUTH_KEY: + /* + * New shared key for SCTP AUTH. Returns 0 on success, -1 otherwise. + */ + + /* Get active key */ + sockopt_len = sizeof(struct sctp_authkeyid); + ret = + getsockopt(b->num, IPPROTO_SCTP, SCTP_AUTH_ACTIVE_KEY, &authkeyid, + &sockopt_len); + if (ret < 0) + break; + + /* Add new key */ + sockopt_len = sizeof(struct sctp_authkey) + 64 * sizeof(uint8_t); + authkey = OPENSSL_malloc(sockopt_len); + if (authkey == NULL) { + ret = -1; + break; + } + memset(authkey, 0, sockopt_len); + authkey->sca_keynumber = authkeyid.scact_keynumber + 1; +# ifndef __FreeBSD__ + /* + * This field is missing in FreeBSD 8.2 and earlier, and FreeBSD 8.3 + * and higher work without it. + */ + authkey->sca_keylength = 64; +# endif + memcpy(&authkey->sca_key[0], ptr, 64 * sizeof(uint8_t)); + + ret = + setsockopt(b->num, IPPROTO_SCTP, SCTP_AUTH_KEY, authkey, + sockopt_len); + OPENSSL_free(authkey); + authkey = NULL; + if (ret < 0) + break; + + /* Reset active key */ + ret = setsockopt(b->num, IPPROTO_SCTP, SCTP_AUTH_ACTIVE_KEY, + &authkeyid, sizeof(struct sctp_authkeyid)); + if (ret < 0) + break; + + break; + case BIO_CTRL_DGRAM_SCTP_NEXT_AUTH_KEY: + /* Returns 0 on success, -1 otherwise. */ + + /* Get active key */ + sockopt_len = sizeof(struct sctp_authkeyid); + ret = + getsockopt(b->num, IPPROTO_SCTP, SCTP_AUTH_ACTIVE_KEY, &authkeyid, + &sockopt_len); + if (ret < 0) + break; + + /* Set active key */ + authkeyid.scact_keynumber = authkeyid.scact_keynumber + 1; + ret = setsockopt(b->num, IPPROTO_SCTP, SCTP_AUTH_ACTIVE_KEY, + &authkeyid, sizeof(struct sctp_authkeyid)); + if (ret < 0) + break; + + /* + * CCS has been sent, so remember that and fall through to check if + * we need to deactivate an old key + */ + data->ccs_sent = 1; + /* fall-through */ + + case BIO_CTRL_DGRAM_SCTP_AUTH_CCS_RCVD: + /* Returns 0 on success, -1 otherwise. */ + + /* + * Has this command really been called or is this just a + * fall-through? + */ + if (cmd == BIO_CTRL_DGRAM_SCTP_AUTH_CCS_RCVD) + data->ccs_rcvd = 1; + + /* + * CSS has been both, received and sent, so deactivate an old key + */ + if (data->ccs_rcvd == 1 && data->ccs_sent == 1) { + /* Get active key */ + sockopt_len = sizeof(struct sctp_authkeyid); + ret = + getsockopt(b->num, IPPROTO_SCTP, SCTP_AUTH_ACTIVE_KEY, + &authkeyid, &sockopt_len); + if (ret < 0) + break; + + /* + * Deactivate key or delete second last key if + * SCTP_AUTHENTICATION_EVENT is not available. + */ + authkeyid.scact_keynumber = authkeyid.scact_keynumber - 1; +# ifdef SCTP_AUTH_DEACTIVATE_KEY + sockopt_len = sizeof(struct sctp_authkeyid); + ret = setsockopt(b->num, IPPROTO_SCTP, SCTP_AUTH_DEACTIVATE_KEY, + &authkeyid, sockopt_len); + if (ret < 0) + break; +# endif +# ifndef SCTP_AUTHENTICATION_EVENT + if (authkeyid.scact_keynumber > 0) { + authkeyid.scact_keynumber = authkeyid.scact_keynumber - 1; + ret = setsockopt(b->num, IPPROTO_SCTP, SCTP_AUTH_DELETE_KEY, + &authkeyid, sizeof(struct sctp_authkeyid)); + if (ret < 0) + break; + } +# endif + + data->ccs_rcvd = 0; + data->ccs_sent = 0; + } + break; + case BIO_CTRL_DGRAM_SCTP_GET_SNDINFO: + /* Returns the size of the copied struct. */ + if (num > (long)sizeof(struct bio_dgram_sctp_sndinfo)) + num = sizeof(struct bio_dgram_sctp_sndinfo); + + memcpy(ptr, &(data->sndinfo), num); + ret = num; + break; + case BIO_CTRL_DGRAM_SCTP_SET_SNDINFO: + /* Returns the size of the copied struct. */ + if (num > (long)sizeof(struct bio_dgram_sctp_sndinfo)) + num = sizeof(struct bio_dgram_sctp_sndinfo); + + memcpy(&(data->sndinfo), ptr, num); + break; + case BIO_CTRL_DGRAM_SCTP_GET_RCVINFO: + /* Returns the size of the copied struct. */ + if (num > (long)sizeof(struct bio_dgram_sctp_rcvinfo)) + num = sizeof(struct bio_dgram_sctp_rcvinfo); + + memcpy(ptr, &data->rcvinfo, num); + + ret = num; + break; + case BIO_CTRL_DGRAM_SCTP_SET_RCVINFO: + /* Returns the size of the copied struct. */ + if (num > (long)sizeof(struct bio_dgram_sctp_rcvinfo)) + num = sizeof(struct bio_dgram_sctp_rcvinfo); + + memcpy(&(data->rcvinfo), ptr, num); + break; + case BIO_CTRL_DGRAM_SCTP_GET_PRINFO: + /* Returns the size of the copied struct. */ + if (num > (long)sizeof(struct bio_dgram_sctp_prinfo)) + num = sizeof(struct bio_dgram_sctp_prinfo); + + memcpy(ptr, &(data->prinfo), num); + ret = num; + break; + case BIO_CTRL_DGRAM_SCTP_SET_PRINFO: + /* Returns the size of the copied struct. */ + if (num > (long)sizeof(struct bio_dgram_sctp_prinfo)) + num = sizeof(struct bio_dgram_sctp_prinfo); + + memcpy(&(data->prinfo), ptr, num); + break; + case BIO_CTRL_DGRAM_SCTP_SAVE_SHUTDOWN: + /* Returns always 1. */ + if (num > 0) + data->save_shutdown = 1; + else + data->save_shutdown = 0; + break; + + default: + /* + * Pass to default ctrl function to process SCTP unspecific commands + */ + ret = dgram_ctrl(b, cmd, num, ptr); + break; + } + return ret; +} + +int BIO_dgram_sctp_notification_cb(BIO *b, + void (*handle_notifications) (BIO *bio, + void + *context, + void *buf), + void *context) +{ + bio_dgram_sctp_data *data = (bio_dgram_sctp_data *) b->ptr; + + if (handle_notifications != NULL) { + data->handle_notifications = handle_notifications; + data->notification_context = context; + } else + return -1; + + return 0; +} + +/* + * BIO_dgram_sctp_wait_for_dry - Wait for SCTP SENDER_DRY event + * @b: The BIO to check for the dry event + * + * Wait until the peer confirms all packets have been received, and so that + * our kernel doesn't have anything to send anymore. This is only received by + * the peer's kernel, not the application. + * + * Returns: + * -1 on error + * 0 when not dry yet + * 1 when dry + */ +int BIO_dgram_sctp_wait_for_dry(BIO *b) +{ + int is_dry = 0; + int sockflags = 0; + int n, ret; + union sctp_notification snp; + struct msghdr msg; + struct iovec iov; +# ifdef SCTP_EVENT + struct sctp_event event; +# else + struct sctp_event_subscribe event; + socklen_t eventsize; +# endif + bio_dgram_sctp_data *data = (bio_dgram_sctp_data *) b->ptr; + + /* set sender dry event */ +# ifdef SCTP_EVENT + memset(&event, 0, sizeof(event)); + event.se_assoc_id = 0; + event.se_type = SCTP_SENDER_DRY_EVENT; + event.se_on = 1; + ret = + setsockopt(b->num, IPPROTO_SCTP, SCTP_EVENT, &event, + sizeof(struct sctp_event)); +# else + eventsize = sizeof(struct sctp_event_subscribe); + ret = getsockopt(b->num, IPPROTO_SCTP, SCTP_EVENTS, &event, &eventsize); + if (ret < 0) + return -1; + + event.sctp_sender_dry_event = 1; + + ret = + setsockopt(b->num, IPPROTO_SCTP, SCTP_EVENTS, &event, + sizeof(struct sctp_event_subscribe)); +# endif + if (ret < 0) + return -1; + + /* peek for notification */ + memset(&snp, 0, sizeof(snp)); + iov.iov_base = (char *)&snp; + iov.iov_len = sizeof(union sctp_notification); + msg.msg_name = NULL; + msg.msg_namelen = 0; + msg.msg_iov = &iov; + msg.msg_iovlen = 1; + msg.msg_control = NULL; + msg.msg_controllen = 0; + msg.msg_flags = 0; + + n = recvmsg(b->num, &msg, MSG_PEEK); + if (n <= 0) { + if ((n < 0) && (get_last_socket_error() != EAGAIN) + && (get_last_socket_error() != EWOULDBLOCK)) + return -1; + else + return 0; + } + + /* if we find a notification, process it and try again if necessary */ + while (msg.msg_flags & MSG_NOTIFICATION) { + memset(&snp, 0, sizeof(snp)); + iov.iov_base = (char *)&snp; + iov.iov_len = sizeof(union sctp_notification); + msg.msg_name = NULL; + msg.msg_namelen = 0; + msg.msg_iov = &iov; + msg.msg_iovlen = 1; + msg.msg_control = NULL; + msg.msg_controllen = 0; + msg.msg_flags = 0; + + n = recvmsg(b->num, &msg, 0); + if (n <= 0) { + if ((n < 0) && (get_last_socket_error() != EAGAIN) + && (get_last_socket_error() != EWOULDBLOCK)) + return -1; + else + return is_dry; + } + + if (snp.sn_header.sn_type == SCTP_SENDER_DRY_EVENT) { + is_dry = 1; + + /* disable sender dry event */ +# ifdef SCTP_EVENT + memset(&event, 0, sizeof(event)); + event.se_assoc_id = 0; + event.se_type = SCTP_SENDER_DRY_EVENT; + event.se_on = 0; + ret = + setsockopt(b->num, IPPROTO_SCTP, SCTP_EVENT, &event, + sizeof(struct sctp_event)); +# else + eventsize = (socklen_t) sizeof(struct sctp_event_subscribe); + ret = + getsockopt(b->num, IPPROTO_SCTP, SCTP_EVENTS, &event, + &eventsize); + if (ret < 0) + return -1; + + event.sctp_sender_dry_event = 0; + + ret = + setsockopt(b->num, IPPROTO_SCTP, SCTP_EVENTS, &event, + sizeof(struct sctp_event_subscribe)); +# endif + if (ret < 0) + return -1; + } +# ifdef SCTP_AUTHENTICATION_EVENT + if (snp.sn_header.sn_type == SCTP_AUTHENTICATION_EVENT) + dgram_sctp_handle_auth_free_key_event(b, &snp); +# endif + + if (data->handle_notifications != NULL) + data->handle_notifications(b, data->notification_context, + (void *)&snp); + + /* found notification, peek again */ + memset(&snp, 0, sizeof(snp)); + iov.iov_base = (char *)&snp; + iov.iov_len = sizeof(union sctp_notification); + msg.msg_name = NULL; + msg.msg_namelen = 0; + msg.msg_iov = &iov; + msg.msg_iovlen = 1; + msg.msg_control = NULL; + msg.msg_controllen = 0; + msg.msg_flags = 0; + + /* if we have seen the dry already, don't wait */ + if (is_dry) { + sockflags = fcntl(b->num, F_GETFL, 0); + fcntl(b->num, F_SETFL, O_NONBLOCK); + } + + n = recvmsg(b->num, &msg, MSG_PEEK); + + if (is_dry) { + fcntl(b->num, F_SETFL, sockflags); + } + + if (n <= 0) { + if ((n < 0) && (get_last_socket_error() != EAGAIN) + && (get_last_socket_error() != EWOULDBLOCK)) + return -1; + else + return is_dry; + } + } + + /* read anything else */ + return is_dry; +} + +int BIO_dgram_sctp_msg_waiting(BIO *b) +{ + int n, sockflags; + union sctp_notification snp; + struct msghdr msg; + struct iovec iov; + bio_dgram_sctp_data *data = (bio_dgram_sctp_data *) b->ptr; + + /* Check if there are any messages waiting to be read */ + do { + memset(&snp, 0, sizeof(snp)); + iov.iov_base = (char *)&snp; + iov.iov_len = sizeof(union sctp_notification); + msg.msg_name = NULL; + msg.msg_namelen = 0; + msg.msg_iov = &iov; + msg.msg_iovlen = 1; + msg.msg_control = NULL; + msg.msg_controllen = 0; + msg.msg_flags = 0; + + sockflags = fcntl(b->num, F_GETFL, 0); + fcntl(b->num, F_SETFL, O_NONBLOCK); + n = recvmsg(b->num, &msg, MSG_PEEK); + fcntl(b->num, F_SETFL, sockflags); + + /* if notification, process and try again */ + if (n > 0 && (msg.msg_flags & MSG_NOTIFICATION)) { +# ifdef SCTP_AUTHENTICATION_EVENT + if (snp.sn_header.sn_type == SCTP_AUTHENTICATION_EVENT) + dgram_sctp_handle_auth_free_key_event(b, &snp); +# endif + + memset(&snp, 0, sizeof(snp)); + iov.iov_base = (char *)&snp; + iov.iov_len = sizeof(union sctp_notification); + msg.msg_name = NULL; + msg.msg_namelen = 0; + msg.msg_iov = &iov; + msg.msg_iovlen = 1; + msg.msg_control = NULL; + msg.msg_controllen = 0; + msg.msg_flags = 0; + n = recvmsg(b->num, &msg, 0); + + if (data->handle_notifications != NULL) + data->handle_notifications(b, data->notification_context, + (void *)&snp); + } + + } while (n > 0 && (msg.msg_flags & MSG_NOTIFICATION)); + + /* Return 1 if there is a message to be read, return 0 otherwise. */ + if (n > 0) + return 1; + else + return 0; +} + +static int dgram_sctp_puts(BIO *bp, const char *str) +{ + int n, ret; + + n = strlen(str); + ret = dgram_sctp_write(bp, str, n); + return ret; +} +# endif + +static int BIO_dgram_should_retry(int i) +{ + int err; + + if ((i == 0) || (i == -1)) { + err = get_last_socket_error(); + +# if defined(OPENSSL_SYS_WINDOWS) + /* + * If the socket return value (i) is -1 and err is unexpectedly 0 at + * this point, the error code was overwritten by another system call + * before this error handling is called. + */ +# endif + + return BIO_dgram_non_fatal_error(err); + } + return 0; +} + +int BIO_dgram_non_fatal_error(int err) +{ + switch (err) { +# if defined(OPENSSL_SYS_WINDOWS) +# if defined(WSAEWOULDBLOCK) + case WSAEWOULDBLOCK: +# endif +# endif + +# ifdef EWOULDBLOCK +# ifdef WSAEWOULDBLOCK +# if WSAEWOULDBLOCK != EWOULDBLOCK + case EWOULDBLOCK: +# endif +# else + case EWOULDBLOCK: +# endif +# endif + +# ifdef EINTR + case EINTR: +# endif + +# ifdef EAGAIN +# if EWOULDBLOCK != EAGAIN + case EAGAIN: +# endif +# endif + +# ifdef EPROTO + case EPROTO: +# endif + +# ifdef EINPROGRESS + case EINPROGRESS: +# endif + +# ifdef EALREADY + case EALREADY: +# endif + + return 1; + default: + break; + } + return 0; +} + +static void get_current_time(struct timeval *t) +{ +# if defined(_WIN32) + SYSTEMTIME st; + union { + unsigned __int64 ul; + FILETIME ft; + } now; + + GetSystemTime(&st); + SystemTimeToFileTime(&st, &now.ft); +# ifdef __MINGW32__ + now.ul -= 116444736000000000ULL; +# else + now.ul -= 116444736000000000UI64; /* re-bias to 1/1/1970 */ +# endif + t->tv_sec = (long)(now.ul / 10000000); + t->tv_usec = ((int)(now.ul % 10000000)) / 10; +# else + gettimeofday(t, NULL); +# endif +} + +#endif diff --git a/roms/edk2/CryptoPkg/Library/OpensslLib/openssl/crypto/bio/bss_fd.c b/roms/edk2/CryptoPkg/Library/OpensslLib/openssl/crypto/bio/bss_fd.c new file mode 100644 index 000000000..ccbe1626b --- /dev/null +++ b/roms/edk2/CryptoPkg/Library/OpensslLib/openssl/crypto/bio/bss_fd.c @@ -0,0 +1,285 @@ +/* + * Copyright 1995-2020 The OpenSSL Project Authors. All Rights Reserved. + * + * Licensed under the OpenSSL license (the "License"). You may not use + * this file except in compliance with the License. You can obtain a copy + * in the file LICENSE in the source distribution or at + * https://www.openssl.org/source/license.html + */ + +#include <stdio.h> +#include <errno.h> + +#include "bio_local.h" + +#if defined(OPENSSL_NO_POSIX_IO) +/* + * Dummy placeholder for BIO_s_fd... + */ +BIO *BIO_new_fd(int fd, int close_flag) +{ + return NULL; +} + +int BIO_fd_non_fatal_error(int err) +{ + return 0; +} + +int BIO_fd_should_retry(int i) +{ + return 0; +} + +const BIO_METHOD *BIO_s_fd(void) +{ + return NULL; +} +#else +/* + * As for unconditional usage of "UPLINK" interface in this module. + * Trouble is that unlike Unix file descriptors [which are indexes + * in kernel-side per-process table], corresponding descriptors on + * platforms which require "UPLINK" interface seem to be indexes + * in a user-land, non-global table. Well, in fact they are indexes + * in stdio _iob[], and recall that _iob[] was the very reason why + * "UPLINK" interface was introduced in first place. But one way on + * another. Neither libcrypto or libssl use this BIO meaning that + * file descriptors can only be provided by application. Therefore + * "UPLINK" calls are due... + */ +static int fd_write(BIO *h, const char *buf, int num); +static int fd_read(BIO *h, char *buf, int size); +static int fd_puts(BIO *h, const char *str); +static int fd_gets(BIO *h, char *buf, int size); +static long fd_ctrl(BIO *h, int cmd, long arg1, void *arg2); +static int fd_new(BIO *h); +static int fd_free(BIO *data); +int BIO_fd_should_retry(int s); + +static const BIO_METHOD methods_fdp = { + BIO_TYPE_FD, + "file descriptor", + /* TODO: Convert to new style write function */ + bwrite_conv, + fd_write, + /* TODO: Convert to new style read function */ + bread_conv, + fd_read, + fd_puts, + fd_gets, + fd_ctrl, + fd_new, + fd_free, + NULL, /* fd_callback_ctrl */ +}; + +const BIO_METHOD *BIO_s_fd(void) +{ + return &methods_fdp; +} + +BIO *BIO_new_fd(int fd, int close_flag) +{ + BIO *ret; + ret = BIO_new(BIO_s_fd()); + if (ret == NULL) + return NULL; + BIO_set_fd(ret, fd, close_flag); + return ret; +} + +static int fd_new(BIO *bi) +{ + bi->init = 0; + bi->num = -1; + bi->ptr = NULL; + bi->flags = BIO_FLAGS_UPLINK; /* essentially redundant */ + return 1; +} + +static int fd_free(BIO *a) +{ + if (a == NULL) + return 0; + if (a->shutdown) { + if (a->init) { + UP_close(a->num); + } + a->init = 0; + a->flags = BIO_FLAGS_UPLINK; + } + return 1; +} + +static int fd_read(BIO *b, char *out, int outl) +{ + int ret = 0; + + if (out != NULL) { + clear_sys_error(); + ret = UP_read(b->num, out, outl); + BIO_clear_retry_flags(b); + if (ret <= 0) { + if (BIO_fd_should_retry(ret)) + BIO_set_retry_read(b); + else if (ret == 0) + b->flags |= BIO_FLAGS_IN_EOF; + } + } + return ret; +} + +static int fd_write(BIO *b, const char *in, int inl) +{ + int ret; + clear_sys_error(); + ret = UP_write(b->num, in, inl); + BIO_clear_retry_flags(b); + if (ret <= 0) { + if (BIO_fd_should_retry(ret)) + BIO_set_retry_write(b); + } + return ret; +} + +static long fd_ctrl(BIO *b, int cmd, long num, void *ptr) +{ + long ret = 1; + int *ip; + + switch (cmd) { + case BIO_CTRL_RESET: + num = 0; + /* fall thru */ + case BIO_C_FILE_SEEK: + ret = (long)UP_lseek(b->num, num, 0); + break; + case BIO_C_FILE_TELL: + case BIO_CTRL_INFO: + ret = (long)UP_lseek(b->num, 0, 1); + break; + case BIO_C_SET_FD: + fd_free(b); + b->num = *((int *)ptr); + b->shutdown = (int)num; + b->init = 1; + break; + case BIO_C_GET_FD: + if (b->init) { + ip = (int *)ptr; + if (ip != NULL) + *ip = b->num; + ret = b->num; + } else + ret = -1; + break; + case BIO_CTRL_GET_CLOSE: + ret = b->shutdown; + break; + case BIO_CTRL_SET_CLOSE: + b->shutdown = (int)num; + break; + case BIO_CTRL_PENDING: + case BIO_CTRL_WPENDING: + ret = 0; + break; + case BIO_CTRL_DUP: + case BIO_CTRL_FLUSH: + ret = 1; + break; + case BIO_CTRL_EOF: + ret = (b->flags & BIO_FLAGS_IN_EOF) != 0 ? 1 : 0; + break; + default: + ret = 0; + break; + } + return ret; +} + +static int fd_puts(BIO *bp, const char *str) +{ + int n, ret; + + n = strlen(str); + ret = fd_write(bp, str, n); + return ret; +} + +static int fd_gets(BIO *bp, char *buf, int size) +{ + int ret = 0; + char *ptr = buf; + char *end = buf + size - 1; + + while (ptr < end && fd_read(bp, ptr, 1) > 0) { + if (*ptr++ == '\n') + break; + } + + ptr[0] = '\0'; + + if (buf[0] != '\0') + ret = strlen(buf); + return ret; +} + +int BIO_fd_should_retry(int i) +{ + int err; + + if ((i == 0) || (i == -1)) { + err = get_last_sys_error(); + + return BIO_fd_non_fatal_error(err); + } + return 0; +} + +int BIO_fd_non_fatal_error(int err) +{ + switch (err) { + +# ifdef EWOULDBLOCK +# ifdef WSAEWOULDBLOCK +# if WSAEWOULDBLOCK != EWOULDBLOCK + case EWOULDBLOCK: +# endif +# else + case EWOULDBLOCK: +# endif +# endif + +# if defined(ENOTCONN) + case ENOTCONN: +# endif + +# ifdef EINTR + case EINTR: +# endif + +# ifdef EAGAIN +# if EWOULDBLOCK != EAGAIN + case EAGAIN: +# endif +# endif + +# ifdef EPROTO + case EPROTO: +# endif + +# ifdef EINPROGRESS + case EINPROGRESS: +# endif + +# ifdef EALREADY + case EALREADY: +# endif + return 1; + default: + break; + } + return 0; +} +#endif diff --git a/roms/edk2/CryptoPkg/Library/OpensslLib/openssl/crypto/bio/bss_file.c b/roms/edk2/CryptoPkg/Library/OpensslLib/openssl/crypto/bio/bss_file.c new file mode 100644 index 000000000..1a70ce799 --- /dev/null +++ b/roms/edk2/CryptoPkg/Library/OpensslLib/openssl/crypto/bio/bss_file.c @@ -0,0 +1,422 @@ +/* + * Copyright 1995-2019 The OpenSSL Project Authors. All Rights Reserved. + * + * Licensed under the OpenSSL license (the "License"). You may not use + * this file except in compliance with the License. You can obtain a copy + * in the file LICENSE in the source distribution or at + * https://www.openssl.org/source/license.html + */ + +#if defined(__linux) || defined(__sun) || defined(__hpux) +/* + * Following definition aliases fopen to fopen64 on above mentioned + * platforms. This makes it possible to open and sequentially access files + * larger than 2GB from 32-bit application. It does not allow to traverse + * them beyond 2GB with fseek/ftell, but on the other hand *no* 32-bit + * platform permits that, not with fseek/ftell. Not to mention that breaking + * 2GB limit for seeking would require surgery to *our* API. But sequential + * access suffices for practical cases when you can run into large files, + * such as fingerprinting, so we can let API alone. For reference, the list + * of 32-bit platforms which allow for sequential access of large files + * without extra "magic" comprise *BSD, Darwin, IRIX... + */ +# ifndef _FILE_OFFSET_BITS +# define _FILE_OFFSET_BITS 64 +# endif +#endif + +#include <stdio.h> +#include <errno.h> +#include "bio_local.h" +#include <openssl/err.h> + +#if !defined(OPENSSL_NO_STDIO) + +static int file_write(BIO *h, const char *buf, int num); +static int file_read(BIO *h, char *buf, int size); +static int file_puts(BIO *h, const char *str); +static int file_gets(BIO *h, char *str, int size); +static long file_ctrl(BIO *h, int cmd, long arg1, void *arg2); +static int file_new(BIO *h); +static int file_free(BIO *data); +static const BIO_METHOD methods_filep = { + BIO_TYPE_FILE, + "FILE pointer", + /* TODO: Convert to new style write function */ + bwrite_conv, + file_write, + /* TODO: Convert to new style read function */ + bread_conv, + file_read, + file_puts, + file_gets, + file_ctrl, + file_new, + file_free, + NULL, /* file_callback_ctrl */ +}; + +BIO *BIO_new_file(const char *filename, const char *mode) +{ + BIO *ret; + FILE *file = openssl_fopen(filename, mode); + int fp_flags = BIO_CLOSE; + + if (strchr(mode, 'b') == NULL) + fp_flags |= BIO_FP_TEXT; + + if (file == NULL) { + SYSerr(SYS_F_FOPEN, get_last_sys_error()); + ERR_add_error_data(5, "fopen('", filename, "','", mode, "')"); + if (errno == ENOENT +#ifdef ENXIO + || errno == ENXIO +#endif + ) + BIOerr(BIO_F_BIO_NEW_FILE, BIO_R_NO_SUCH_FILE); + else + BIOerr(BIO_F_BIO_NEW_FILE, ERR_R_SYS_LIB); + return NULL; + } + if ((ret = BIO_new(BIO_s_file())) == NULL) { + fclose(file); + return NULL; + } + + BIO_clear_flags(ret, BIO_FLAGS_UPLINK); /* we did fopen -> we disengage + * UPLINK */ + BIO_set_fp(ret, file, fp_flags); + return ret; +} + +BIO *BIO_new_fp(FILE *stream, int close_flag) +{ + BIO *ret; + + if ((ret = BIO_new(BIO_s_file())) == NULL) + return NULL; + + /* redundant flag, left for documentation purposes */ + BIO_set_flags(ret, BIO_FLAGS_UPLINK); + BIO_set_fp(ret, stream, close_flag); + return ret; +} + +const BIO_METHOD *BIO_s_file(void) +{ + return &methods_filep; +} + +static int file_new(BIO *bi) +{ + bi->init = 0; + bi->num = 0; + bi->ptr = NULL; + bi->flags = BIO_FLAGS_UPLINK; /* default to UPLINK */ + return 1; +} + +static int file_free(BIO *a) +{ + if (a == NULL) + return 0; + if (a->shutdown) { + if ((a->init) && (a->ptr != NULL)) { + if (a->flags & BIO_FLAGS_UPLINK) + UP_fclose(a->ptr); + else + fclose(a->ptr); + a->ptr = NULL; + a->flags = BIO_FLAGS_UPLINK; + } + a->init = 0; + } + return 1; +} + +static int file_read(BIO *b, char *out, int outl) +{ + int ret = 0; + + if (b->init && (out != NULL)) { + if (b->flags & BIO_FLAGS_UPLINK) + ret = UP_fread(out, 1, (int)outl, b->ptr); + else + ret = fread(out, 1, (int)outl, (FILE *)b->ptr); + if (ret == 0 + && (b->flags & BIO_FLAGS_UPLINK) ? UP_ferror((FILE *)b->ptr) : + ferror((FILE *)b->ptr)) { + SYSerr(SYS_F_FREAD, get_last_sys_error()); + BIOerr(BIO_F_FILE_READ, ERR_R_SYS_LIB); + ret = -1; + } + } + return ret; +} + +static int file_write(BIO *b, const char *in, int inl) +{ + int ret = 0; + + if (b->init && (in != NULL)) { + if (b->flags & BIO_FLAGS_UPLINK) + ret = UP_fwrite(in, (int)inl, 1, b->ptr); + else + ret = fwrite(in, (int)inl, 1, (FILE *)b->ptr); + if (ret) + ret = inl; + /* ret=fwrite(in,1,(int)inl,(FILE *)b->ptr); */ + /* + * according to Tim Hudson <tjh@openssl.org>, the commented out + * version above can cause 'inl' write calls under some stupid stdio + * implementations (VMS) + */ + } + return ret; +} + +static long file_ctrl(BIO *b, int cmd, long num, void *ptr) +{ + long ret = 1; + FILE *fp = (FILE *)b->ptr; + FILE **fpp; + char p[4]; + int st; + + switch (cmd) { + case BIO_C_FILE_SEEK: + case BIO_CTRL_RESET: + if (b->flags & BIO_FLAGS_UPLINK) + ret = (long)UP_fseek(b->ptr, num, 0); + else + ret = (long)fseek(fp, num, 0); + break; + case BIO_CTRL_EOF: + if (b->flags & BIO_FLAGS_UPLINK) + ret = (long)UP_feof(fp); + else + ret = (long)feof(fp); + break; + case BIO_C_FILE_TELL: + case BIO_CTRL_INFO: + if (b->flags & BIO_FLAGS_UPLINK) + ret = UP_ftell(b->ptr); + else + ret = ftell(fp); + break; + case BIO_C_SET_FILE_PTR: + file_free(b); + b->shutdown = (int)num & BIO_CLOSE; + b->ptr = ptr; + b->init = 1; +# if BIO_FLAGS_UPLINK!=0 +# if defined(__MINGW32__) && defined(__MSVCRT__) && !defined(_IOB_ENTRIES) +# define _IOB_ENTRIES 20 +# endif + /* Safety net to catch purely internal BIO_set_fp calls */ +# if defined(_MSC_VER) && _MSC_VER>=1900 + if (ptr == stdin || ptr == stdout || ptr == stderr) + BIO_clear_flags(b, BIO_FLAGS_UPLINK); +# elif defined(_IOB_ENTRIES) + if ((size_t)ptr >= (size_t)stdin && + (size_t)ptr < (size_t)(stdin + _IOB_ENTRIES)) + BIO_clear_flags(b, BIO_FLAGS_UPLINK); +# endif +# endif +# ifdef UP_fsetmod + if (b->flags & BIO_FLAGS_UPLINK) + UP_fsetmod(b->ptr, (char)((num & BIO_FP_TEXT) ? 't' : 'b')); + else +# endif + { +# if defined(OPENSSL_SYS_WINDOWS) + int fd = _fileno((FILE *)ptr); + if (num & BIO_FP_TEXT) + _setmode(fd, _O_TEXT); + else + _setmode(fd, _O_BINARY); +# elif defined(OPENSSL_SYS_MSDOS) + int fd = fileno((FILE *)ptr); + /* Set correct text/binary mode */ + if (num & BIO_FP_TEXT) + _setmode(fd, _O_TEXT); + /* Dangerous to set stdin/stdout to raw (unless redirected) */ + else { + if (fd == STDIN_FILENO || fd == STDOUT_FILENO) { + if (isatty(fd) <= 0) + _setmode(fd, _O_BINARY); + } else + _setmode(fd, _O_BINARY); + } +# elif defined(OPENSSL_SYS_WIN32_CYGWIN) + int fd = fileno((FILE *)ptr); + if (!(num & BIO_FP_TEXT)) + setmode(fd, O_BINARY); +# endif + } + break; + case BIO_C_SET_FILENAME: + file_free(b); + b->shutdown = (int)num & BIO_CLOSE; + if (num & BIO_FP_APPEND) { + if (num & BIO_FP_READ) + OPENSSL_strlcpy(p, "a+", sizeof(p)); + else + OPENSSL_strlcpy(p, "a", sizeof(p)); + } else if ((num & BIO_FP_READ) && (num & BIO_FP_WRITE)) + OPENSSL_strlcpy(p, "r+", sizeof(p)); + else if (num & BIO_FP_WRITE) + OPENSSL_strlcpy(p, "w", sizeof(p)); + else if (num & BIO_FP_READ) + OPENSSL_strlcpy(p, "r", sizeof(p)); + else { + BIOerr(BIO_F_FILE_CTRL, BIO_R_BAD_FOPEN_MODE); + ret = 0; + break; + } +# if defined(OPENSSL_SYS_MSDOS) || defined(OPENSSL_SYS_WINDOWS) + if (!(num & BIO_FP_TEXT)) + OPENSSL_strlcat(p, "b", sizeof(p)); + else + OPENSSL_strlcat(p, "t", sizeof(p)); +# elif defined(OPENSSL_SYS_WIN32_CYGWIN) + if (!(num & BIO_FP_TEXT)) + OPENSSL_strlcat(p, "b", sizeof(p)); +# endif + fp = openssl_fopen(ptr, p); + if (fp == NULL) { + SYSerr(SYS_F_FOPEN, get_last_sys_error()); + ERR_add_error_data(5, "fopen('", ptr, "','", p, "')"); + BIOerr(BIO_F_FILE_CTRL, ERR_R_SYS_LIB); + ret = 0; + break; + } + b->ptr = fp; + b->init = 1; + BIO_clear_flags(b, BIO_FLAGS_UPLINK); /* we did fopen -> we disengage + * UPLINK */ + break; + case BIO_C_GET_FILE_PTR: + /* the ptr parameter is actually a FILE ** in this case. */ + if (ptr != NULL) { + fpp = (FILE **)ptr; + *fpp = (FILE *)b->ptr; + } + break; + case BIO_CTRL_GET_CLOSE: + ret = (long)b->shutdown; + break; + case BIO_CTRL_SET_CLOSE: + b->shutdown = (int)num; + break; + case BIO_CTRL_FLUSH: + st = b->flags & BIO_FLAGS_UPLINK + ? UP_fflush(b->ptr) : fflush((FILE *)b->ptr); + if (st == EOF) { + SYSerr(SYS_F_FFLUSH, get_last_sys_error()); + ERR_add_error_data(1, "fflush()"); + BIOerr(BIO_F_FILE_CTRL, ERR_R_SYS_LIB); + ret = 0; + } + break; + case BIO_CTRL_DUP: + ret = 1; + break; + + case BIO_CTRL_WPENDING: + case BIO_CTRL_PENDING: + case BIO_CTRL_PUSH: + case BIO_CTRL_POP: + default: + ret = 0; + break; + } + return ret; +} + +static int file_gets(BIO *bp, char *buf, int size) +{ + int ret = 0; + + buf[0] = '\0'; + if (bp->flags & BIO_FLAGS_UPLINK) { + if (!UP_fgets(buf, size, bp->ptr)) + goto err; + } else { + if (!fgets(buf, size, (FILE *)bp->ptr)) + goto err; + } + if (buf[0] != '\0') + ret = strlen(buf); + err: + return ret; +} + +static int file_puts(BIO *bp, const char *str) +{ + int n, ret; + + n = strlen(str); + ret = file_write(bp, str, n); + return ret; +} + +#else + +static int file_write(BIO *b, const char *in, int inl) +{ + return -1; +} +static int file_read(BIO *b, char *out, int outl) +{ + return -1; +} +static int file_puts(BIO *bp, const char *str) +{ + return -1; +} +static int file_gets(BIO *bp, char *buf, int size) +{ + return 0; +} +static long file_ctrl(BIO *b, int cmd, long num, void *ptr) +{ + return 0; +} +static int file_new(BIO *bi) +{ + return 0; +} +static int file_free(BIO *a) +{ + return 0; +} + +static const BIO_METHOD methods_filep = { + BIO_TYPE_FILE, + "FILE pointer", + /* TODO: Convert to new style write function */ + bwrite_conv, + file_write, + /* TODO: Convert to new style read function */ + bread_conv, + file_read, + file_puts, + file_gets, + file_ctrl, + file_new, + file_free, + NULL, /* file_callback_ctrl */ +}; + +const BIO_METHOD *BIO_s_file(void) +{ + return &methods_filep; +} + +BIO *BIO_new_file(const char *filename, const char *mode) +{ + return NULL; +} + +#endif /* OPENSSL_NO_STDIO */ diff --git a/roms/edk2/CryptoPkg/Library/OpensslLib/openssl/crypto/bio/bss_log.c b/roms/edk2/CryptoPkg/Library/OpensslLib/openssl/crypto/bio/bss_log.c new file mode 100644 index 000000000..b9579faaa --- /dev/null +++ b/roms/edk2/CryptoPkg/Library/OpensslLib/openssl/crypto/bio/bss_log.c @@ -0,0 +1,416 @@ +/* + * Copyright 1999-2018 The OpenSSL Project Authors. All Rights Reserved. + * + * Licensed under the OpenSSL license (the "License"). You may not use + * this file except in compliance with the License. You can obtain a copy + * in the file LICENSE in the source distribution or at + * https://www.openssl.org/source/license.html + */ + +/* + * Why BIO_s_log? + * + * BIO_s_log is useful for system daemons (or services under NT). It is + * one-way BIO, it sends all stuff to syslogd (on system that commonly use + * that), or event log (on NT), or OPCOM (on OpenVMS). + * + */ + +#include <stdio.h> +#include <errno.h> + +#include "bio_local.h" +#include "internal/cryptlib.h" + +#if defined(OPENSSL_SYS_WINCE) +#elif defined(OPENSSL_SYS_WIN32) +#elif defined(OPENSSL_SYS_VMS) +# include <opcdef.h> +# include <descrip.h> +# include <lib$routines.h> +# include <starlet.h> +/* Some compiler options may mask the declaration of "_malloc32". */ +# if __INITIAL_POINTER_SIZE && defined _ANSI_C_SOURCE +# if __INITIAL_POINTER_SIZE == 64 +# pragma pointer_size save +# pragma pointer_size 32 +void *_malloc32(__size_t); +# pragma pointer_size restore +# endif /* __INITIAL_POINTER_SIZE == 64 */ +# endif /* __INITIAL_POINTER_SIZE && defined + * _ANSI_C_SOURCE */ +#elif defined(__DJGPP__) && defined(OPENSSL_NO_SOCK) +# define NO_SYSLOG +#elif (!defined(MSDOS) || defined(WATT32)) && !defined(OPENSSL_SYS_VXWORKS) && !defined(NO_SYSLOG) +# include <syslog.h> +#endif + +#include <openssl/buffer.h> +#include <openssl/err.h> + +#ifndef NO_SYSLOG + +# if defined(OPENSSL_SYS_WIN32) +# define LOG_EMERG 0 +# define LOG_ALERT 1 +# define LOG_CRIT 2 +# define LOG_ERR 3 +# define LOG_WARNING 4 +# define LOG_NOTICE 5 +# define LOG_INFO 6 +# define LOG_DEBUG 7 + +# define LOG_DAEMON (3<<3) +# elif defined(OPENSSL_SYS_VMS) +/* On VMS, we don't really care about these, but we need them to compile */ +# define LOG_EMERG 0 +# define LOG_ALERT 1 +# define LOG_CRIT 2 +# define LOG_ERR 3 +# define LOG_WARNING 4 +# define LOG_NOTICE 5 +# define LOG_INFO 6 +# define LOG_DEBUG 7 + +# define LOG_DAEMON OPC$M_NM_NTWORK +# endif + +static int slg_write(BIO *h, const char *buf, int num); +static int slg_puts(BIO *h, const char *str); +static long slg_ctrl(BIO *h, int cmd, long arg1, void *arg2); +static int slg_new(BIO *h); +static int slg_free(BIO *data); +static void xopenlog(BIO *bp, char *name, int level); +static void xsyslog(BIO *bp, int priority, const char *string); +static void xcloselog(BIO *bp); + +static const BIO_METHOD methods_slg = { + BIO_TYPE_MEM, + "syslog", + /* TODO: Convert to new style write function */ + bwrite_conv, + slg_write, + NULL, /* slg_write_old, */ + NULL, /* slg_read, */ + slg_puts, + NULL, + slg_ctrl, + slg_new, + slg_free, + NULL, /* slg_callback_ctrl */ +}; + +const BIO_METHOD *BIO_s_log(void) +{ + return &methods_slg; +} + +static int slg_new(BIO *bi) +{ + bi->init = 1; + bi->num = 0; + bi->ptr = NULL; + xopenlog(bi, "application", LOG_DAEMON); + return 1; +} + +static int slg_free(BIO *a) +{ + if (a == NULL) + return 0; + xcloselog(a); + return 1; +} + +static int slg_write(BIO *b, const char *in, int inl) +{ + int ret = inl; + char *buf; + char *pp; + int priority, i; + static const struct { + int strl; + char str[10]; + int log_level; + } mapping[] = { + { + 6, "PANIC ", LOG_EMERG + }, + { + 6, "EMERG ", LOG_EMERG + }, + { + 4, "EMR ", LOG_EMERG + }, + { + 6, "ALERT ", LOG_ALERT + }, + { + 4, "ALR ", LOG_ALERT + }, + { + 5, "CRIT ", LOG_CRIT + }, + { + 4, "CRI ", LOG_CRIT + }, + { + 6, "ERROR ", LOG_ERR + }, + { + 4, "ERR ", LOG_ERR + }, + { + 8, "WARNING ", LOG_WARNING + }, + { + 5, "WARN ", LOG_WARNING + }, + { + 4, "WAR ", LOG_WARNING + }, + { + 7, "NOTICE ", LOG_NOTICE + }, + { + 5, "NOTE ", LOG_NOTICE + }, + { + 4, "NOT ", LOG_NOTICE + }, + { + 5, "INFO ", LOG_INFO + }, + { + 4, "INF ", LOG_INFO + }, + { + 6, "DEBUG ", LOG_DEBUG + }, + { + 4, "DBG ", LOG_DEBUG + }, + { + 0, "", LOG_ERR + } + /* The default */ + }; + + if ((buf = OPENSSL_malloc(inl + 1)) == NULL) { + BIOerr(BIO_F_SLG_WRITE, ERR_R_MALLOC_FAILURE); + return 0; + } + memcpy(buf, in, inl); + buf[inl] = '\0'; + + i = 0; + while (strncmp(buf, mapping[i].str, mapping[i].strl) != 0) + i++; + priority = mapping[i].log_level; + pp = buf + mapping[i].strl; + + xsyslog(b, priority, pp); + + OPENSSL_free(buf); + return ret; +} + +static long slg_ctrl(BIO *b, int cmd, long num, void *ptr) +{ + switch (cmd) { + case BIO_CTRL_SET: + xcloselog(b); + xopenlog(b, ptr, num); + break; + default: + break; + } + return 0; +} + +static int slg_puts(BIO *bp, const char *str) +{ + int n, ret; + + n = strlen(str); + ret = slg_write(bp, str, n); + return ret; +} + +# if defined(OPENSSL_SYS_WIN32) + +static void xopenlog(BIO *bp, char *name, int level) +{ + if (check_winnt()) + bp->ptr = RegisterEventSourceA(NULL, name); + else + bp->ptr = NULL; +} + +static void xsyslog(BIO *bp, int priority, const char *string) +{ + LPCSTR lpszStrings[2]; + WORD evtype = EVENTLOG_ERROR_TYPE; + char pidbuf[DECIMAL_SIZE(DWORD) + 4]; + + if (bp->ptr == NULL) + return; + + switch (priority) { + case LOG_EMERG: + case LOG_ALERT: + case LOG_CRIT: + case LOG_ERR: + evtype = EVENTLOG_ERROR_TYPE; + break; + case LOG_WARNING: + evtype = EVENTLOG_WARNING_TYPE; + break; + case LOG_NOTICE: + case LOG_INFO: + case LOG_DEBUG: + evtype = EVENTLOG_INFORMATION_TYPE; + break; + default: + /* + * Should never happen, but set it + * as error anyway. + */ + evtype = EVENTLOG_ERROR_TYPE; + break; + } + + sprintf(pidbuf, "[%lu] ", GetCurrentProcessId()); + lpszStrings[0] = pidbuf; + lpszStrings[1] = string; + + ReportEventA(bp->ptr, evtype, 0, 1024, NULL, 2, 0, lpszStrings, NULL); +} + +static void xcloselog(BIO *bp) +{ + if (bp->ptr) + DeregisterEventSource((HANDLE) (bp->ptr)); + bp->ptr = NULL; +} + +# elif defined(OPENSSL_SYS_VMS) + +static int VMS_OPC_target = LOG_DAEMON; + +static void xopenlog(BIO *bp, char *name, int level) +{ + VMS_OPC_target = level; +} + +static void xsyslog(BIO *bp, int priority, const char *string) +{ + struct dsc$descriptor_s opc_dsc; + +/* Arrange 32-bit pointer to opcdef buffer and malloc(), if needed. */ +# if __INITIAL_POINTER_SIZE == 64 +# pragma pointer_size save +# pragma pointer_size 32 +# define OPCDEF_TYPE __char_ptr32 +# define OPCDEF_MALLOC _malloc32 +# else /* __INITIAL_POINTER_SIZE == 64 */ +# define OPCDEF_TYPE char * +# define OPCDEF_MALLOC OPENSSL_malloc +# endif /* __INITIAL_POINTER_SIZE == 64 [else] */ + + struct opcdef *opcdef_p; + +# if __INITIAL_POINTER_SIZE == 64 +# pragma pointer_size restore +# endif /* __INITIAL_POINTER_SIZE == 64 */ + + char buf[10240]; + unsigned int len; + struct dsc$descriptor_s buf_dsc; + $DESCRIPTOR(fao_cmd, "!AZ: !AZ"); + char *priority_tag; + + switch (priority) { + case LOG_EMERG: + priority_tag = "Emergency"; + break; + case LOG_ALERT: + priority_tag = "Alert"; + break; + case LOG_CRIT: + priority_tag = "Critical"; + break; + case LOG_ERR: + priority_tag = "Error"; + break; + case LOG_WARNING: + priority_tag = "Warning"; + break; + case LOG_NOTICE: + priority_tag = "Notice"; + break; + case LOG_INFO: + priority_tag = "Info"; + break; + case LOG_DEBUG: + priority_tag = "DEBUG"; + break; + } + + buf_dsc.dsc$b_dtype = DSC$K_DTYPE_T; + buf_dsc.dsc$b_class = DSC$K_CLASS_S; + buf_dsc.dsc$a_pointer = buf; + buf_dsc.dsc$w_length = sizeof(buf) - 1; + + lib$sys_fao(&fao_cmd, &len, &buf_dsc, priority_tag, string); + + /* We know there's an 8-byte header. That's documented. */ + opcdef_p = OPCDEF_MALLOC(8 + len); + opcdef_p->opc$b_ms_type = OPC$_RQ_RQST; + memcpy(opcdef_p->opc$z_ms_target_classes, &VMS_OPC_target, 3); + opcdef_p->opc$l_ms_rqstid = 0; + memcpy(&opcdef_p->opc$l_ms_text, buf, len); + + opc_dsc.dsc$b_dtype = DSC$K_DTYPE_T; + opc_dsc.dsc$b_class = DSC$K_CLASS_S; + opc_dsc.dsc$a_pointer = (OPCDEF_TYPE) opcdef_p; + opc_dsc.dsc$w_length = len + 8; + + sys$sndopr(opc_dsc, 0); + + OPENSSL_free(opcdef_p); +} + +static void xcloselog(BIO *bp) +{ +} + +# else /* Unix/Watt32 */ + +static void xopenlog(BIO *bp, char *name, int level) +{ +# ifdef WATT32 /* djgpp/DOS */ + openlog(name, LOG_PID | LOG_CONS | LOG_NDELAY, level); +# else + openlog(name, LOG_PID | LOG_CONS, level); +# endif +} + +static void xsyslog(BIO *bp, int priority, const char *string) +{ + syslog(priority, "%s", string); +} + +static void xcloselog(BIO *bp) +{ + closelog(); +} + +# endif /* Unix */ + +#else /* NO_SYSLOG */ +const BIO_METHOD *BIO_s_log(void) +{ + return NULL; +} +#endif /* NO_SYSLOG */ diff --git a/roms/edk2/CryptoPkg/Library/OpensslLib/openssl/crypto/bio/bss_mem.c b/roms/edk2/CryptoPkg/Library/OpensslLib/openssl/crypto/bio/bss_mem.c new file mode 100644 index 000000000..7cb4a5781 --- /dev/null +++ b/roms/edk2/CryptoPkg/Library/OpensslLib/openssl/crypto/bio/bss_mem.c @@ -0,0 +1,372 @@ +/* + * Copyright 1995-2019 The OpenSSL Project Authors. All Rights Reserved. + * + * Licensed under the OpenSSL license (the "License"). You may not use + * this file except in compliance with the License. You can obtain a copy + * in the file LICENSE in the source distribution or at + * https://www.openssl.org/source/license.html + */ + +#include <stdio.h> +#include <errno.h> +#include "bio_local.h" +#include "internal/cryptlib.h" + +static int mem_write(BIO *h, const char *buf, int num); +static int mem_read(BIO *h, char *buf, int size); +static int mem_puts(BIO *h, const char *str); +static int mem_gets(BIO *h, char *str, int size); +static long mem_ctrl(BIO *h, int cmd, long arg1, void *arg2); +static int mem_new(BIO *h); +static int secmem_new(BIO *h); +static int mem_free(BIO *data); +static int mem_buf_free(BIO *data); +static int mem_buf_sync(BIO *h); + +static const BIO_METHOD mem_method = { + BIO_TYPE_MEM, + "memory buffer", + /* TODO: Convert to new style write function */ + bwrite_conv, + mem_write, + /* TODO: Convert to new style read function */ + bread_conv, + mem_read, + mem_puts, + mem_gets, + mem_ctrl, + mem_new, + mem_free, + NULL, /* mem_callback_ctrl */ +}; + +static const BIO_METHOD secmem_method = { + BIO_TYPE_MEM, + "secure memory buffer", + /* TODO: Convert to new style write function */ + bwrite_conv, + mem_write, + /* TODO: Convert to new style read function */ + bread_conv, + mem_read, + mem_puts, + mem_gets, + mem_ctrl, + secmem_new, + mem_free, + NULL, /* mem_callback_ctrl */ +}; + +/* + * BIO memory stores buffer and read pointer + * however the roles are different for read only BIOs. + * In that case the readp just stores the original state + * to be used for reset. + */ +typedef struct bio_buf_mem_st { + struct buf_mem_st *buf; /* allocated buffer */ + struct buf_mem_st *readp; /* read pointer */ +} BIO_BUF_MEM; + +/* + * bio->num is used to hold the value to return on 'empty', if it is 0, + * should_retry is not set + */ + +const BIO_METHOD *BIO_s_mem(void) +{ + return &mem_method; +} + +const BIO_METHOD *BIO_s_secmem(void) +{ + return(&secmem_method); +} + +BIO *BIO_new_mem_buf(const void *buf, int len) +{ + BIO *ret; + BUF_MEM *b; + BIO_BUF_MEM *bb; + size_t sz; + + if (buf == NULL) { + BIOerr(BIO_F_BIO_NEW_MEM_BUF, BIO_R_NULL_PARAMETER); + return NULL; + } + sz = (len < 0) ? strlen(buf) : (size_t)len; + if ((ret = BIO_new(BIO_s_mem())) == NULL) + return NULL; + bb = (BIO_BUF_MEM *)ret->ptr; + b = bb->buf; + /* Cast away const and trust in the MEM_RDONLY flag. */ + b->data = (void *)buf; + b->length = sz; + b->max = sz; + *bb->readp = *bb->buf; + ret->flags |= BIO_FLAGS_MEM_RDONLY; + /* Since this is static data retrying won't help */ + ret->num = 0; + return ret; +} + +static int mem_init(BIO *bi, unsigned long flags) +{ + BIO_BUF_MEM *bb = OPENSSL_zalloc(sizeof(*bb)); + + if (bb == NULL) + return 0; + if ((bb->buf = BUF_MEM_new_ex(flags)) == NULL) { + OPENSSL_free(bb); + return 0; + } + if ((bb->readp = OPENSSL_zalloc(sizeof(*bb->readp))) == NULL) { + BUF_MEM_free(bb->buf); + OPENSSL_free(bb); + return 0; + } + *bb->readp = *bb->buf; + bi->shutdown = 1; + bi->init = 1; + bi->num = -1; + bi->ptr = (char *)bb; + return 1; +} + +static int mem_new(BIO *bi) +{ + return mem_init(bi, 0L); +} + +static int secmem_new(BIO *bi) +{ + return mem_init(bi, BUF_MEM_FLAG_SECURE); +} + +static int mem_free(BIO *a) +{ + BIO_BUF_MEM *bb; + + if (a == NULL) + return 0; + + bb = (BIO_BUF_MEM *)a->ptr; + if (!mem_buf_free(a)) + return 0; + OPENSSL_free(bb->readp); + OPENSSL_free(bb); + return 1; +} + +static int mem_buf_free(BIO *a) +{ + if (a == NULL) + return 0; + + if (a->shutdown && a->init && a->ptr != NULL) { + BIO_BUF_MEM *bb = (BIO_BUF_MEM *)a->ptr; + BUF_MEM *b = bb->buf; + + if (a->flags & BIO_FLAGS_MEM_RDONLY) + b->data = NULL; + BUF_MEM_free(b); + } + return 1; +} + +/* + * Reallocate memory buffer if read pointer differs + */ +static int mem_buf_sync(BIO *b) +{ + if (b != NULL && b->init != 0 && b->ptr != NULL) { + BIO_BUF_MEM *bbm = (BIO_BUF_MEM *)b->ptr; + + if (bbm->readp->data != bbm->buf->data) { + memmove(bbm->buf->data, bbm->readp->data, bbm->readp->length); + bbm->buf->length = bbm->readp->length; + bbm->readp->data = bbm->buf->data; + } + } + return 0; +} + +static int mem_read(BIO *b, char *out, int outl) +{ + int ret = -1; + BIO_BUF_MEM *bbm = (BIO_BUF_MEM *)b->ptr; + BUF_MEM *bm = bbm->readp; + + if (b->flags & BIO_FLAGS_MEM_RDONLY) + bm = bbm->buf; + BIO_clear_retry_flags(b); + ret = (outl >= 0 && (size_t)outl > bm->length) ? (int)bm->length : outl; + if ((out != NULL) && (ret > 0)) { + memcpy(out, bm->data, ret); + bm->length -= ret; + bm->max -= ret; + bm->data += ret; + } else if (bm->length == 0) { + ret = b->num; + if (ret != 0) + BIO_set_retry_read(b); + } + return ret; +} + +static int mem_write(BIO *b, const char *in, int inl) +{ + int ret = -1; + int blen; + BIO_BUF_MEM *bbm = (BIO_BUF_MEM *)b->ptr; + + if (in == NULL) { + BIOerr(BIO_F_MEM_WRITE, BIO_R_NULL_PARAMETER); + goto end; + } + if (b->flags & BIO_FLAGS_MEM_RDONLY) { + BIOerr(BIO_F_MEM_WRITE, BIO_R_WRITE_TO_READ_ONLY_BIO); + goto end; + } + BIO_clear_retry_flags(b); + if (inl == 0) + return 0; + blen = bbm->readp->length; + mem_buf_sync(b); + if (BUF_MEM_grow_clean(bbm->buf, blen + inl) == 0) + goto end; + memcpy(bbm->buf->data + blen, in, inl); + *bbm->readp = *bbm->buf; + ret = inl; + end: + return ret; +} + +static long mem_ctrl(BIO *b, int cmd, long num, void *ptr) +{ + long ret = 1; + char **pptr; + BIO_BUF_MEM *bbm = (BIO_BUF_MEM *)b->ptr; + BUF_MEM *bm; + + if (b->flags & BIO_FLAGS_MEM_RDONLY) + bm = bbm->buf; + else + bm = bbm->readp; + + switch (cmd) { + case BIO_CTRL_RESET: + bm = bbm->buf; + if (bm->data != NULL) { + if (!(b->flags & BIO_FLAGS_MEM_RDONLY)) { + if (!(b->flags & BIO_FLAGS_NONCLEAR_RST)) { + memset(bm->data, 0, bm->max); + bm->length = 0; + } + *bbm->readp = *bbm->buf; + } else { + /* For read only case just reset to the start again */ + *bbm->buf = *bbm->readp; + } + } + break; + case BIO_CTRL_EOF: + ret = (long)(bm->length == 0); + break; + case BIO_C_SET_BUF_MEM_EOF_RETURN: + b->num = (int)num; + break; + case BIO_CTRL_INFO: + ret = (long)bm->length; + if (ptr != NULL) { + pptr = (char **)ptr; + *pptr = (char *)&(bm->data[0]); + } + break; + case BIO_C_SET_BUF_MEM: + mem_buf_free(b); + b->shutdown = (int)num; + bbm->buf = ptr; + *bbm->readp = *bbm->buf; + break; + case BIO_C_GET_BUF_MEM_PTR: + if (ptr != NULL) { + if (!(b->flags & BIO_FLAGS_MEM_RDONLY)) + mem_buf_sync(b); + bm = bbm->buf; + pptr = (char **)ptr; + *pptr = (char *)bm; + } + break; + case BIO_CTRL_GET_CLOSE: + ret = (long)b->shutdown; + break; + case BIO_CTRL_SET_CLOSE: + b->shutdown = (int)num; + break; + case BIO_CTRL_WPENDING: + ret = 0L; + break; + case BIO_CTRL_PENDING: + ret = (long)bm->length; + break; + case BIO_CTRL_DUP: + case BIO_CTRL_FLUSH: + ret = 1; + break; + case BIO_CTRL_PUSH: + case BIO_CTRL_POP: + default: + ret = 0; + break; + } + return ret; +} + +static int mem_gets(BIO *bp, char *buf, int size) +{ + int i, j; + int ret = -1; + char *p; + BIO_BUF_MEM *bbm = (BIO_BUF_MEM *)bp->ptr; + BUF_MEM *bm = bbm->readp; + + if (bp->flags & BIO_FLAGS_MEM_RDONLY) + bm = bbm->buf; + BIO_clear_retry_flags(bp); + j = bm->length; + if ((size - 1) < j) + j = size - 1; + if (j <= 0) { + *buf = '\0'; + return 0; + } + p = bm->data; + for (i = 0; i < j; i++) { + if (p[i] == '\n') { + i++; + break; + } + } + + /* + * i is now the max num of bytes to copy, either j or up to + * and including the first newline + */ + + i = mem_read(bp, buf, i); + if (i > 0) + buf[i] = '\0'; + ret = i; + return ret; +} + +static int mem_puts(BIO *bp, const char *str) +{ + int n, ret; + + n = strlen(str); + ret = mem_write(bp, str, n); + /* memory semantics is that it will always work */ + return ret; +} diff --git a/roms/edk2/CryptoPkg/Library/OpensslLib/openssl/crypto/bio/bss_null.c b/roms/edk2/CryptoPkg/Library/OpensslLib/openssl/crypto/bio/bss_null.c new file mode 100644 index 000000000..e73ce7841 --- /dev/null +++ b/roms/edk2/CryptoPkg/Library/OpensslLib/openssl/crypto/bio/bss_null.c @@ -0,0 +1,87 @@ +/* + * Copyright 1995-2018 The OpenSSL Project Authors. All Rights Reserved. + * + * Licensed under the OpenSSL license (the "License"). You may not use + * this file except in compliance with the License. You can obtain a copy + * in the file LICENSE in the source distribution or at + * https://www.openssl.org/source/license.html + */ + +#include <stdio.h> +#include <errno.h> +#include "bio_local.h" +#include "internal/cryptlib.h" + +static int null_write(BIO *h, const char *buf, int num); +static int null_read(BIO *h, char *buf, int size); +static int null_puts(BIO *h, const char *str); +static int null_gets(BIO *h, char *str, int size); +static long null_ctrl(BIO *h, int cmd, long arg1, void *arg2); +static const BIO_METHOD null_method = { + BIO_TYPE_NULL, + "NULL", + /* TODO: Convert to new style write function */ + bwrite_conv, + null_write, + /* TODO: Convert to new style read function */ + bread_conv, + null_read, + null_puts, + null_gets, + null_ctrl, + NULL, + NULL, + NULL, /* null_callback_ctrl */ +}; + +const BIO_METHOD *BIO_s_null(void) +{ + return &null_method; +} + +static int null_read(BIO *b, char *out, int outl) +{ + return 0; +} + +static int null_write(BIO *b, const char *in, int inl) +{ + return inl; +} + +static long null_ctrl(BIO *b, int cmd, long num, void *ptr) +{ + long ret = 1; + + switch (cmd) { + case BIO_CTRL_RESET: + case BIO_CTRL_EOF: + case BIO_CTRL_SET: + case BIO_CTRL_SET_CLOSE: + case BIO_CTRL_FLUSH: + case BIO_CTRL_DUP: + ret = 1; + break; + case BIO_CTRL_GET_CLOSE: + case BIO_CTRL_INFO: + case BIO_CTRL_GET: + case BIO_CTRL_PENDING: + case BIO_CTRL_WPENDING: + default: + ret = 0; + break; + } + return ret; +} + +static int null_gets(BIO *bp, char *buf, int size) +{ + return 0; +} + +static int null_puts(BIO *bp, const char *str) +{ + if (str == NULL) + return 0; + return strlen(str); +} diff --git a/roms/edk2/CryptoPkg/Library/OpensslLib/openssl/crypto/bio/bss_sock.c b/roms/edk2/CryptoPkg/Library/OpensslLib/openssl/crypto/bio/bss_sock.c new file mode 100644 index 000000000..6251f3d46 --- /dev/null +++ b/roms/edk2/CryptoPkg/Library/OpensslLib/openssl/crypto/bio/bss_sock.c @@ -0,0 +1,238 @@ +/* + * Copyright 1995-2020 The OpenSSL Project Authors. All Rights Reserved. + * + * Licensed under the OpenSSL license (the "License"). You may not use + * this file except in compliance with the License. You can obtain a copy + * in the file LICENSE in the source distribution or at + * https://www.openssl.org/source/license.html + */ + +#include <stdio.h> +#include <errno.h> +#include "bio_local.h" +#include "internal/cryptlib.h" + +#ifndef OPENSSL_NO_SOCK + +# include <openssl/bio.h> + +# ifdef WATT32 +/* Watt-32 uses same names */ +# undef sock_write +# undef sock_read +# undef sock_puts +# define sock_write SockWrite +# define sock_read SockRead +# define sock_puts SockPuts +# endif + +static int sock_write(BIO *h, const char *buf, int num); +static int sock_read(BIO *h, char *buf, int size); +static int sock_puts(BIO *h, const char *str); +static long sock_ctrl(BIO *h, int cmd, long arg1, void *arg2); +static int sock_new(BIO *h); +static int sock_free(BIO *data); +int BIO_sock_should_retry(int s); + +static const BIO_METHOD methods_sockp = { + BIO_TYPE_SOCKET, + "socket", + /* TODO: Convert to new style write function */ + bwrite_conv, + sock_write, + /* TODO: Convert to new style read function */ + bread_conv, + sock_read, + sock_puts, + NULL, /* sock_gets, */ + sock_ctrl, + sock_new, + sock_free, + NULL, /* sock_callback_ctrl */ +}; + +const BIO_METHOD *BIO_s_socket(void) +{ + return &methods_sockp; +} + +BIO *BIO_new_socket(int fd, int close_flag) +{ + BIO *ret; + + ret = BIO_new(BIO_s_socket()); + if (ret == NULL) + return NULL; + BIO_set_fd(ret, fd, close_flag); + return ret; +} + +static int sock_new(BIO *bi) +{ + bi->init = 0; + bi->num = 0; + bi->ptr = NULL; + bi->flags = 0; + return 1; +} + +static int sock_free(BIO *a) +{ + if (a == NULL) + return 0; + if (a->shutdown) { + if (a->init) { + BIO_closesocket(a->num); + } + a->init = 0; + a->flags = 0; + } + return 1; +} + +static int sock_read(BIO *b, char *out, int outl) +{ + int ret = 0; + + if (out != NULL) { + clear_socket_error(); + ret = readsocket(b->num, out, outl); + BIO_clear_retry_flags(b); + if (ret <= 0) { + if (BIO_sock_should_retry(ret)) + BIO_set_retry_read(b); + else if (ret == 0) + b->flags |= BIO_FLAGS_IN_EOF; + } + } + return ret; +} + +static int sock_write(BIO *b, const char *in, int inl) +{ + int ret; + + clear_socket_error(); + ret = writesocket(b->num, in, inl); + BIO_clear_retry_flags(b); + if (ret <= 0) { + if (BIO_sock_should_retry(ret)) + BIO_set_retry_write(b); + } + return ret; +} + +static long sock_ctrl(BIO *b, int cmd, long num, void *ptr) +{ + long ret = 1; + int *ip; + + switch (cmd) { + case BIO_C_SET_FD: + sock_free(b); + b->num = *((int *)ptr); + b->shutdown = (int)num; + b->init = 1; + break; + case BIO_C_GET_FD: + if (b->init) { + ip = (int *)ptr; + if (ip != NULL) + *ip = b->num; + ret = b->num; + } else + ret = -1; + break; + case BIO_CTRL_GET_CLOSE: + ret = b->shutdown; + break; + case BIO_CTRL_SET_CLOSE: + b->shutdown = (int)num; + break; + case BIO_CTRL_DUP: + case BIO_CTRL_FLUSH: + ret = 1; + break; + case BIO_CTRL_EOF: + ret = (b->flags & BIO_FLAGS_IN_EOF) != 0 ? 1 : 0; + break; + default: + ret = 0; + break; + } + return ret; +} + +static int sock_puts(BIO *bp, const char *str) +{ + int n, ret; + + n = strlen(str); + ret = sock_write(bp, str, n); + return ret; +} + +int BIO_sock_should_retry(int i) +{ + int err; + + if ((i == 0) || (i == -1)) { + err = get_last_socket_error(); + + return BIO_sock_non_fatal_error(err); + } + return 0; +} + +int BIO_sock_non_fatal_error(int err) +{ + switch (err) { +# if defined(OPENSSL_SYS_WINDOWS) +# if defined(WSAEWOULDBLOCK) + case WSAEWOULDBLOCK: +# endif +# endif + +# ifdef EWOULDBLOCK +# ifdef WSAEWOULDBLOCK +# if WSAEWOULDBLOCK != EWOULDBLOCK + case EWOULDBLOCK: +# endif +# else + case EWOULDBLOCK: +# endif +# endif + +# if defined(ENOTCONN) + case ENOTCONN: +# endif + +# ifdef EINTR + case EINTR: +# endif + +# ifdef EAGAIN +# if EWOULDBLOCK != EAGAIN + case EAGAIN: +# endif +# endif + +# ifdef EPROTO + case EPROTO: +# endif + +# ifdef EINPROGRESS + case EINPROGRESS: +# endif + +# ifdef EALREADY + case EALREADY: +# endif + return 1; + default: + break; + } + return 0; +} + +#endif /* #ifndef OPENSSL_NO_SOCK */ diff --git a/roms/edk2/CryptoPkg/Library/OpensslLib/openssl/crypto/bio/build.info b/roms/edk2/CryptoPkg/Library/OpensslLib/openssl/crypto/bio/build.info new file mode 100644 index 000000000..d1e7d73c5 --- /dev/null +++ b/roms/edk2/CryptoPkg/Library/OpensslLib/openssl/crypto/bio/build.info @@ -0,0 +1,8 @@ +LIBS=../../libcrypto +SOURCE[../../libcrypto]=\ + bio_lib.c bio_cb.c bio_err.c \ + bss_mem.c bss_null.c bss_fd.c \ + bss_file.c bss_sock.c bss_conn.c \ + bf_null.c bf_buff.c b_print.c b_dump.c b_addr.c \ + b_sock.c b_sock2.c bss_acpt.c bf_nbio.c bss_log.c bss_bio.c \ + bss_dgram.c bio_meth.c bf_lbuf.c |