int SSL_CTX_use_serverinfo_file(SSL_CTX *ctx, const char *file)
{
    unsigned char *serverinfo = NULL;
    unsigned char *tmp;
    size_t serverinfo_length = 0;
    unsigned char *extension = 0;
    long extension_length = 0;
    char *name = NULL;
    char *header = NULL;
    char namePrefix1[] = "SERVERINFO FOR ";
    char namePrefix2[] = "SERVERINFOV2 FOR ";
    int ret = 0;
    BIO *bin = NULL;
    size_t num_extensions = 0, contextoff = 0;
    if (ctx == NULL || file == NULL) {
        SSLerr(SSL_F_SSL_CTX_USE_SERVERINFO_FILE, ERR_R_PASSED_NULL_PARAMETER);
        goto end;
    }
    bin = BIO_new(BIO_s_file());
    if (bin == NULL) {
        SSLerr(SSL_F_SSL_CTX_USE_SERVERINFO_FILE, ERR_R_BUF_LIB);
        goto end;
    }
    if (BIO_read_filename(bin, file) <= 0) {
        SSLerr(SSL_F_SSL_CTX_USE_SERVERINFO_FILE, ERR_R_SYS_LIB);
        goto end;
    }
    for (num_extensions = 0;; num_extensions++) {
        unsigned int version;
        if (PEM_read_bio(bin, &name, &header, &extension, &extension_length)
            == 0) {
            if (num_extensions == 0) {
                SSLerr(SSL_F_SSL_CTX_USE_SERVERINFO_FILE,
                       SSL_R_NO_PEM_EXTENSIONS);
                goto end;
            } else
                break;
        }
        if (strlen(name) < strlen(namePrefix1)) {
            SSLerr(SSL_F_SSL_CTX_USE_SERVERINFO_FILE, SSL_R_PEM_NAME_TOO_SHORT);
            goto end;
        }
        if (strncmp(name, namePrefix1, strlen(namePrefix1)) == 0) {
            version = SSL_SERVERINFOV1;
        } else {
            if (strlen(name) < strlen(namePrefix2)) {
                SSLerr(SSL_F_SSL_CTX_USE_SERVERINFO_FILE,
                       SSL_R_PEM_NAME_TOO_SHORT);
                goto end;
            }
            if (strncmp(name, namePrefix2, strlen(namePrefix2)) != 0) {
                SSLerr(SSL_F_SSL_CTX_USE_SERVERINFO_FILE,
                       SSL_R_PEM_NAME_BAD_PREFIX);
                goto end;
            }
            version = SSL_SERVERINFOV2;
        }
        if (version == SSL_SERVERINFOV1) {
            if (extension_length < 4
                    || (extension[2] << 8) + extension[3]
                       != extension_length - 4) {
                SSLerr(SSL_F_SSL_CTX_USE_SERVERINFO_FILE, SSL_R_BAD_DATA);
                goto end;
            }
            contextoff = 4;
        } else {
            if (extension_length < 8
                    || (extension[6] << 8) + extension[7]
                       != extension_length - 8) {
                SSLerr(SSL_F_SSL_CTX_USE_SERVERINFO_FILE, SSL_R_BAD_DATA);
                goto end;
            }
        }
        tmp = OPENSSL_realloc(serverinfo, serverinfo_length + extension_length
                                          + contextoff);
        if (tmp == NULL) {
            SSLerr(SSL_F_SSL_CTX_USE_SERVERINFO_FILE, ERR_R_MALLOC_FAILURE);
            goto end;
        }
        serverinfo = tmp;
        if (contextoff > 0) {
            unsigned char *sinfo = serverinfo + serverinfo_length;
            sinfo[0] = 0;
            sinfo[1] = 0;
            sinfo[2] = (SYNTHV1CONTEXT >> 8) & 0xff;
            sinfo[3] = SYNTHV1CONTEXT & 0xff;
        }
        memcpy(serverinfo + serverinfo_length + contextoff,
               extension, extension_length);
        serverinfo_length += extension_length + contextoff;
        OPENSSL_free(name);
        name = NULL;
        OPENSSL_free(header);
        header = NULL;
        OPENSSL_free(extension);
        extension = NULL;
    }
    ret = SSL_CTX_use_serverinfo_ex(ctx, SSL_SERVERINFOV2, serverinfo,
                                    serverinfo_length);
 end:
    OPENSSL_free(name);
    OPENSSL_free(header);
    OPENSSL_free(extension);
    OPENSSL_free(serverinfo);
    BIO_free(bin);
    return ret;
}
['int SSL_CTX_use_serverinfo_file(SSL_CTX *ctx, const char *file)\n{\n    unsigned char *serverinfo = NULL;\n    unsigned char *tmp;\n    size_t serverinfo_length = 0;\n    unsigned char *extension = 0;\n    long extension_length = 0;\n    char *name = NULL;\n    char *header = NULL;\n    char namePrefix1[] = "SERVERINFO FOR ";\n    char namePrefix2[] = "SERVERINFOV2 FOR ";\n    int ret = 0;\n    BIO *bin = NULL;\n    size_t num_extensions = 0, contextoff = 0;\n    if (ctx == NULL || file == NULL) {\n        SSLerr(SSL_F_SSL_CTX_USE_SERVERINFO_FILE, ERR_R_PASSED_NULL_PARAMETER);\n        goto end;\n    }\n    bin = BIO_new(BIO_s_file());\n    if (bin == NULL) {\n        SSLerr(SSL_F_SSL_CTX_USE_SERVERINFO_FILE, ERR_R_BUF_LIB);\n        goto end;\n    }\n    if (BIO_read_filename(bin, file) <= 0) {\n        SSLerr(SSL_F_SSL_CTX_USE_SERVERINFO_FILE, ERR_R_SYS_LIB);\n        goto end;\n    }\n    for (num_extensions = 0;; num_extensions++) {\n        unsigned int version;\n        if (PEM_read_bio(bin, &name, &header, &extension, &extension_length)\n            == 0) {\n            if (num_extensions == 0) {\n                SSLerr(SSL_F_SSL_CTX_USE_SERVERINFO_FILE,\n                       SSL_R_NO_PEM_EXTENSIONS);\n                goto end;\n            } else\n                break;\n        }\n        if (strlen(name) < strlen(namePrefix1)) {\n            SSLerr(SSL_F_SSL_CTX_USE_SERVERINFO_FILE, SSL_R_PEM_NAME_TOO_SHORT);\n            goto end;\n        }\n        if (strncmp(name, namePrefix1, strlen(namePrefix1)) == 0) {\n            version = SSL_SERVERINFOV1;\n        } else {\n            if (strlen(name) < strlen(namePrefix2)) {\n                SSLerr(SSL_F_SSL_CTX_USE_SERVERINFO_FILE,\n                       SSL_R_PEM_NAME_TOO_SHORT);\n                goto end;\n            }\n            if (strncmp(name, namePrefix2, strlen(namePrefix2)) != 0) {\n                SSLerr(SSL_F_SSL_CTX_USE_SERVERINFO_FILE,\n                       SSL_R_PEM_NAME_BAD_PREFIX);\n                goto end;\n            }\n            version = SSL_SERVERINFOV2;\n        }\n        if (version == SSL_SERVERINFOV1) {\n            if (extension_length < 4\n                    || (extension[2] << 8) + extension[3]\n                       != extension_length - 4) {\n                SSLerr(SSL_F_SSL_CTX_USE_SERVERINFO_FILE, SSL_R_BAD_DATA);\n                goto end;\n            }\n            contextoff = 4;\n        } else {\n            if (extension_length < 8\n                    || (extension[6] << 8) + extension[7]\n                       != extension_length - 8) {\n                SSLerr(SSL_F_SSL_CTX_USE_SERVERINFO_FILE, SSL_R_BAD_DATA);\n                goto end;\n            }\n        }\n        tmp = OPENSSL_realloc(serverinfo, serverinfo_length + extension_length\n                                          + contextoff);\n        if (tmp == NULL) {\n            SSLerr(SSL_F_SSL_CTX_USE_SERVERINFO_FILE, ERR_R_MALLOC_FAILURE);\n            goto end;\n        }\n        serverinfo = tmp;\n        if (contextoff > 0) {\n            unsigned char *sinfo = serverinfo + serverinfo_length;\n            sinfo[0] = 0;\n            sinfo[1] = 0;\n            sinfo[2] = (SYNTHV1CONTEXT >> 8) & 0xff;\n            sinfo[3] = SYNTHV1CONTEXT & 0xff;\n        }\n        memcpy(serverinfo + serverinfo_length + contextoff,\n               extension, extension_length);\n        serverinfo_length += extension_length + contextoff;\n        OPENSSL_free(name);\n        name = NULL;\n        OPENSSL_free(header);\n        header = NULL;\n        OPENSSL_free(extension);\n        extension = NULL;\n    }\n    ret = SSL_CTX_use_serverinfo_ex(ctx, SSL_SERVERINFOV2, serverinfo,\n                                    serverinfo_length);\n end:\n    OPENSSL_free(name);\n    OPENSSL_free(header);\n    OPENSSL_free(extension);\n    OPENSSL_free(serverinfo);\n    BIO_free(bin);\n    return ret;\n}', 'int PEM_read_bio(BIO *bp, char **name, char **header, unsigned char **data,\n                 long *len)\n{\n    return PEM_read_bio_ex(bp, name, header, data, len, PEM_FLAG_EAY_COMPATIBLE);\n}', "int PEM_read_bio_ex(BIO *bp, char **name_out, char **header,\n                    unsigned char **data, long *len_out, unsigned int flags)\n{\n    EVP_ENCODE_CTX *ctx = EVP_ENCODE_CTX_new();\n    const BIO_METHOD *bmeth;\n    BIO *headerB = NULL, *dataB = NULL;\n    char *name = NULL;\n    int len, taillen, headerlen, ret = 0;\n    BUF_MEM * buf_mem;\n    if (ctx == NULL) {\n        PEMerr(PEM_F_PEM_READ_BIO_EX, ERR_R_MALLOC_FAILURE);\n        return 0;\n    }\n    *len_out = 0;\n    *name_out = *header = NULL;\n    *data = NULL;\n    if ((flags & PEM_FLAG_EAY_COMPATIBLE) && (flags & PEM_FLAG_ONLY_B64)) {\n        PEMerr(PEM_F_PEM_READ_BIO_EX, ERR_R_PASSED_INVALID_ARGUMENT);\n        goto end;\n    }\n    bmeth = (flags & PEM_FLAG_SECURE) ? BIO_s_secmem() : BIO_s_mem();\n    headerB = BIO_new(bmeth);\n    dataB = BIO_new(bmeth);\n    if (headerB == NULL || dataB == NULL) {\n        PEMerr(PEM_F_PEM_READ_BIO_EX, ERR_R_MALLOC_FAILURE);\n        goto end;\n    }\n    if (!get_name(bp, &name, flags))\n        goto end;\n    if (!get_header_and_data(bp, &headerB, &dataB, name, flags))\n        goto end;\n    EVP_DecodeInit(ctx);\n    BIO_get_mem_ptr(dataB, &buf_mem);\n    len = buf_mem->length;\n    if (EVP_DecodeUpdate(ctx, (unsigned char*)buf_mem->data, &len,\n                         (unsigned char*)buf_mem->data, len) < 0\n            || EVP_DecodeFinal(ctx, (unsigned char*)&(buf_mem->data[len]),\n                               &taillen) < 0) {\n        PEMerr(PEM_F_PEM_READ_BIO_EX, PEM_R_BAD_BASE64_DECODE);\n        goto end;\n    }\n    len += taillen;\n    buf_mem->length = len;\n    if (len == 0)\n        goto end;\n    headerlen = BIO_get_mem_data(headerB, NULL);\n    *header = pem_malloc(headerlen + 1, flags);\n    *data = pem_malloc(len, flags);\n    if (*header == NULL || *data == NULL) {\n        pem_free(*header, flags);\n        pem_free(*data, flags);\n        goto end;\n    }\n    BIO_read(headerB, *header, headerlen);\n    (*header)[headerlen] = '\\0';\n    BIO_read(dataB, *data, len);\n    *len_out = len;\n    *name_out = name;\n    name = NULL;\n    ret = 1;\nend:\n    EVP_ENCODE_CTX_free(ctx);\n    pem_free(name, flags);\n    BIO_free(headerB);\n    BIO_free(dataB);\n    return ret;\n}"]