예제 #1
1
int main (int argc, char *argv[])
{
    ngx_pool_t *pool;
    ngx_str_t dst, src = ngx_string("cubicdaiya");
    u_char *encoded;
    size_t encoded_len;

    encoded_len = ngx_base64_encoded_length(src.len);
    pool        = ngx_create_pool(NGX_DEFAULT_POOL_SIZE, NULL);
    if (pool == NULL) {
        perror("ngx_create_pool() failed.");
        return 1;
    }
    if ((encoded = ngx_pcalloc(pool, encoded_len + 1)) == NULL) {
        perror("ngx_pcalloc() failed.");
        return 1;
    }

    dst.data = encoded;
    dst.len  = encoded_len;
    ngx_encode_base64(&dst, &src);

    printf("src:%s, dst:%s\n", src.data, dst.data);

    return 0;
}
static char *ngx_http_acme_create_jwk(ngx_conf_t *cf, void *conf, RSA *key, json_t **jwk)
{
    ngx_str_t e, n, tmp;

    /* Baser64url encode e */
    tmp.len = BN_num_bytes(key->e);
    tmp.data = ngx_alloc(tmp.len, cf->log);
    tmp.len = BN_bn2bin(key->e, tmp.data);
    e.len = ngx_base64_encoded_length(tmp.len);
    e.data = ngx_alloc(e.len, cf->log);
    ngx_encode_base64url(&e, &tmp);
    ngx_free(tmp.data);

    /* Baser64url encode n */
    tmp.len = BN_num_bytes(key->n);
    tmp.data = ngx_alloc(tmp.len, cf->log);
    tmp.len = BN_bn2bin(key->n, tmp.data);
    n.len = ngx_base64_encoded_length(tmp.len);
    n.data = ngx_alloc(n.len, cf->log);
    ngx_encode_base64url(&n, &tmp);
    ngx_free(tmp.data);

    *jwk = json_pack("{s:s, s:s%, s:s%}", "kty", "RSA", "e", e.data, e.len, "n", n.data, n.len);
    if(*jwk == NULL) {
        ngx_log_error(NGX_LOG_ERR, cf->log, 0, "Failed to pack JWK");
        return NGX_CONF_ERROR;
    }

    ngx_free(e.data);
    ngx_free(n.data);

    return NGX_CONF_OK;
} /* ngx_http_acme_create_jwk */
static ngx_str_t *
ngx_http_push_stream_generate_websocket_accept_value(ngx_http_request_t *r, ngx_str_t *sec_key, ngx_pool_t *temp_pool)
{
#if (NGX_HAVE_SHA1)
    ngx_str_t    *sha1_signed, *accept_value;
    ngx_sha1_t   sha1;

    sha1_signed = ngx_http_push_stream_create_str(temp_pool, NGX_HTTP_PUSH_STREAM_WEBSOCKET_SHA1_SIGNED_HASH_LENGTH);
    accept_value = ngx_http_push_stream_create_str(r->pool, ngx_base64_encoded_length(NGX_HTTP_PUSH_STREAM_WEBSOCKET_SHA1_SIGNED_HASH_LENGTH));

    if ((sha1_signed == NULL) || (accept_value == NULL)) {
        return NULL;
    }

    ngx_sha1_init(&sha1);
    ngx_sha1_update(&sha1, sec_key->data, sec_key->len);
    ngx_sha1_update(&sha1, NGX_HTTP_PUSH_STREAM_WEBSOCKET_SIGN_KEY.data, NGX_HTTP_PUSH_STREAM_WEBSOCKET_SIGN_KEY.len);
    ngx_sha1_final(sha1_signed->data, &sha1);

    ngx_encode_base64(accept_value, sha1_signed);

    return accept_value;
#else
    return NULL;
#endif
}
예제 #4
0
int main(int argc, char* argv[]) {
    /* str to lower */
    ngx_str_t str = ngx_string("Hello World!");
    u_char* strlow = (u_char*)malloc(str.len);
    ngx_strlow(strlow, str.data, str.len);
    fprintf(stdout, "strlow %.*s\n", str.len, strlow);
    free(strlow);

    /* base64 encode and decode */
    ngx_str_t raw_str = ngx_string("123abc"); 
    ngx_str_t base64_encoded_str = ngx_null_string; 
    ngx_str_t base64_decoded_str = ngx_null_string;

    base64_encoded_str.len = ngx_base64_encoded_length(raw_str.len);
    base64_encoded_str.data = (u_char*)malloc(base64_encoded_str.len);
    ngx_encode_base64(&base64_encoded_str, &raw_str);
    fprintf(stdout, "%.*s\n", base64_encoded_str.len, base64_encoded_str.data);

    base64_decoded_str.len = ngx_base64_decoded_length(base64_encoded_str.len);
    base64_decoded_str.data = (u_char*)malloc(base64_decoded_str.len);
    ngx_decode_base64(&base64_decoded_str, &base64_encoded_str);
    fprintf(stdout, "%.*s\n", base64_decoded_str.len, base64_decoded_str.data);
    free(base64_encoded_str.data);
    free(base64_decoded_str.data);

    return 0;
}
static int
ngx_http_lua_ngx_encode_base64(lua_State *L)
{
    ngx_str_t                p, src;

    if (lua_gettop(L) != 1) {
        return luaL_error(L, "expecting one argument");
    }

    if (lua_isnil(L, 1)) {
        src.data = (u_char *) "";
        src.len = 0;

    } else {
        src.data = (u_char *) luaL_checklstring(L, 1, &src.len);
    }

    p.len = ngx_base64_encoded_length(src.len);

    p.data = lua_newuserdata(L, p.len);

    ngx_encode_base64(&p, &src);

    lua_pushlstring(L, (char *) p.data, p.len);

    return 1;
}
예제 #6
0
파일: websocket.c 프로젝트: inzahgi/nchan
static void websocket_perform_handshake(full_subscriber_t *fsub) {
  static ngx_str_t    magic = ngx_string("258EAFA5-E914-47DA-95CA-C5AB0DC85B11");
  ngx_str_t           ws_accept_key, sha1_str;
  u_char              buf_sha1[21];
  u_char              buf[255];
  ngx_str_t          *tmp, *ws_key;
  ngx_int_t           ws_version;
  ngx_http_request_t *r = fsub->sub.request;
  
  ngx_sha1_t          sha1;
  
  ws_accept_key.data = buf;
  
  r->headers_out.content_length_n = 0;
  r->header_only = 1;  
  
  if((tmp = nchan_get_header_value(r, NCHAN_HEADER_SEC_WEBSOCKET_VERSION)) == NULL) {
    r->headers_out.status = NGX_HTTP_BAD_REQUEST;
    fsub->sub.dequeue_after_response=1;
  }
  else {
    ws_version=ngx_atoi(tmp->data, tmp->len);
    if(ws_version != 13) {
      r->headers_out.status = NGX_HTTP_BAD_REQUEST;
      fsub->sub.dequeue_after_response=1;
    }
  }
  
  if((ws_key = nchan_get_header_value(r, NCHAN_HEADER_SEC_WEBSOCKET_KEY)) == NULL) {
    r->headers_out.status = NGX_HTTP_BAD_REQUEST;
    fsub->sub.dequeue_after_response=1;
  }
  
  if(r->headers_out.status != NGX_HTTP_BAD_REQUEST) {
    //generate accept key
    ngx_sha1_init(&sha1);
    ngx_sha1_update(&sha1, ws_key->data, ws_key->len);
    ngx_sha1_update(&sha1, magic.data, magic.len);
    ngx_sha1_final(buf_sha1, &sha1);
    sha1_str.len=20;
    sha1_str.data=buf_sha1;
    
    ws_accept_key.len=ngx_base64_encoded_length(sha1_str.len);
    assert(ws_accept_key.len < 255);
    ngx_encode_base64(&ws_accept_key, &sha1_str);
    
    nchan_include_access_control_if_needed(r, fsub->ctx);
    nchan_add_response_header(r, &NCHAN_HEADER_SEC_WEBSOCKET_ACCEPT, &ws_accept_key);
    nchan_add_response_header(r, &NCHAN_HEADER_UPGRADE, &NCHAN_WEBSOCKET);
#if nginx_version < 1003013
    nchan_add_response_header(r, &NCHAN_HEADER_CONNECTION, &NCHAN_UPGRADE);
#endif
    r->headers_out.status_line = NCHAN_HTTP_STATUS_101;
    r->headers_out.status = NGX_HTTP_SWITCHING_PROTOCOLS;
    
    r->keepalive=0; //apparently, websocket must not use keepalive.
  }
  
  ngx_http_send_header(r);
}
예제 #7
0
/*
 * Because 'remote_user' is assumed to be provided by basic authorization
 * (see ngx_http_variable_remote_user) we are forced to create bogus
 * non-Negotiate authorization header. This may possibly clobber Negotiate
 * token too soon.
 */
    ngx_int_t
ngx_http_auth_spnego_set_bogus_authorization(
        ngx_http_request_t *r)
{
    const char *bogus_passwd = "bogus_auth_gss_passwd";
    ngx_str_t plain, encoded, final;

    if (r->headers_in.user.len == 0) {
        spnego_debug0("ngx_http_auth_spnego_set_bogus_authorization: no user NGX_DECLINED");
        return NGX_DECLINED;
    }

    /* +1 because of the ":" in "user:password" */
    plain.len = r->headers_in.user.len + ngx_strlen(bogus_passwd) + 1;
    plain.data = ngx_pnalloc(r->pool, plain.len);
    if (NULL == plain.data) {
        return NGX_ERROR;
    }

    ngx_snprintf(plain.data, plain.len, "%V:%s",
            &r->headers_in.user, bogus_passwd);

    encoded.len = ngx_base64_encoded_length(plain.len);
    encoded.data = ngx_pnalloc(r->pool, encoded.len);
    if (NULL == encoded.data) {
        return NGX_ERROR;
    }

    ngx_encode_base64(&encoded, &plain);

    final.len = sizeof("Basic ") + encoded.len - 1;
예제 #8
0
ngx_int_t
ngx_mail_auth_cram_md5_salt(ngx_mail_session_t *s, ngx_connection_t *c,
    char *prefix, size_t len)
{
    u_char      *p;
    ngx_str_t    salt;
    ngx_uint_t   n;

    p = ngx_palloc(c->pool, len + ngx_base64_encoded_length(s->salt.len) + 2);
    if (p == NULL) {
        return NGX_ERROR;
    }

    salt.data = ngx_cpymem(p, prefix, len);
    s->salt.len -= 2;

    ngx_encode_base64(&salt, &s->salt);

    s->salt.len += 2;
    n = len + salt.len;
    p[n++] = CR; p[n++] = LF;

    s->out.len = n;
    s->out.data = p;

    return NGX_OK;
}
예제 #9
0
파일: ngx_str_t.c 프로젝트: bekars/NginB
int main()
{
    u_char *p = NULL;
    ngx_uint_t size;
    ngx_str_t dst;
    ngx_str_t mystr = ngx_string("hello, world !");
    ngx_keyval_t pair = {ngx_string("url"), ngx_string("http://rainx.cn/index.php?test=1")};
    int dst_len = ngx_base64_encoded_length(mystr.len);
    printf("source length is %d, destination length is %d\n", mystr.len, dst_len);
    p = malloc(ngx_base64_encoded_length(mystr.len) + 1);
    dst.data = p;
    ngx_encode_base64(&dst, &mystr);
    printf("source str is %s\ndestination str is %s\n", mystr.data, dst.data);
    free(p);
    size = pair.value.len + 2 * ngx_escape_uri(NULL, pair.value.data, pair.value.len, NGX_ESCAPE_URI);
    p = malloc(size * sizeof(u_char));
    ngx_escape_uri(p, pair.value.data, pair.value.len, NGX_ESCAPE_URI);
    printf("escaped %s is : %s (%d)\noriginal url size is %d\n", pair.key.data, p, size, pair.value.len);
    free(p);
    return 0;
}
static mrb_value ngx_http_mruby_base64_encode(mrb_state *mrb, mrb_value self)
{
    mrb_value mrb_src;
    ngx_str_t src, dst;

    mrb_get_args(mrb, "o", &mrb_src);
    mrb_src = mrb_obj_as_string(mrb, mrb_src);

    src.data = (u_char *)RSTRING_PTR(mrb_src);
    src.len  = RSTRING_LEN(mrb_src);

    dst.len  = ngx_base64_encoded_length(src.len);
    dst.data = mrb_malloc(mrb, dst.len + 1);

    ngx_encode_base64(&dst, &src);

    return mrb_str_new(mrb, (char *)dst.data, dst.len);
}
예제 #11
0
static int
ngx_http_lua_ngx_encode_base64(lua_State *L)
{
    ngx_http_request_t      *r;
    ngx_str_t                p, src;

    lua_pushlightuserdata(L, &ngx_http_lua_request_key);
    lua_rawget(L, LUA_GLOBALSINDEX);
    r = lua_touserdata(L, -1);
    lua_pop(L, 1);

    if (r == NULL) {
        return luaL_error(L, "no request object found");
    }

    if (lua_gettop(L) != 1) {
        return luaL_error(L, "expecting one argument");
    }

    if (strcmp(luaL_typename(L, 1), (char *) "nil") == 0) {
        src.data     = (u_char *) "";
        src.len      = 0;

    } else {
        src.data = (u_char *) luaL_checklstring(L, 1, &src.len);
    }

    p.len = ngx_base64_encoded_length(src.len);

    p.data = ngx_palloc(r->pool, p.len);
    if (p.data == NULL) {
        return NGX_ERROR;
    }

    ngx_encode_base64(&p, &src);

    lua_pushlstring(L, (char *) p.data, p.len);

    ngx_pfree(r->pool, p.data);

    return 1;
}
예제 #12
0
파일: sample.c 프로젝트: qtkmz/dojo
static void sample_base64()
{
	ngx_str_t src = ngx_string("test_string");
	ngx_str_t base64;

    base64.len = ngx_base64_encoded_length(src.len);
    base64.data = malloc(base64.len);
    if (base64.data == NULL) {
		fprintf(stderr, "Error: malloc() failed.");
        return;
    }

	ngx_encode_base64(&base64, &src);

	puts("sample_base64 --------");
	printf("string = [%.*s]\n", src.len, src.data);
	printf("base64 = [%.*s]\n", base64.len, base64.data);

	return;
}
static mrb_value ngx_http_mruby_base64_encode(mrb_state *mrb, mrb_value self)
{
    mrb_value mrb_src;
    ngx_str_t src, dst;

    mrb_get_args(mrb, "o", &mrb_src);

    if (mrb_type(mrb_src) != MRB_TT_STRING) {
        mrb_src = mrb_funcall(mrb, mrb_src, "to_s", 0, NULL);
    }

    src.data = (u_char *)RSTRING_PTR(mrb_src);
    src.len  = RSTRING_LEN(mrb_src);

    dst.len  = ngx_base64_encoded_length(src.len);
    dst.data = mrb_malloc(mrb, dst.len + 1);

    ngx_encode_base64(&dst, &src);

    return mrb_str_new(mrb, (char *)dst.data, dst.len);
}
예제 #14
0
static ngx_int_t
ngx_lua_smtp_handle_response(ngx_lua_smtp_ctx_t *ctx)
{
    u_char      *p, *last;
    ngx_str_t    dst, src, *to;
    ngx_buf_t   *b;
    ngx_uint_t   i;
    enum {
        sw_start = 0,
        sw_helo,
        sw_login,
        sw_user,
        sw_passwd,
        sw_from,
        sw_to,
        sw_data,
        sw_quit,
        sw_done
    } state;

    ngx_log_debug0(NGX_LOG_DEBUG_CORE, ngx_cycle->log, 0,
                   "lua smtp handle response");

    b = ctx->response;

    if (b->last - b->pos < 4) {
        return NGX_AGAIN;
    }

    if (*(b->last - 2) != CR || *(b->last - 1) != LF) {
        if (b->last == b->end) {
            *(b->last - 1) = '\0';
            ngx_log_error(NGX_LOG_ERR, ngx_cycle->log, 0,
                          "stmp server sent too long response line: \"%s\"",
                          b->pos);
            return NGX_ERROR;
        }

        return NGX_AGAIN;
    }

    p = b->pos;
    last = b->last;

    b = ctx->request;
    b->pos = b->start;

    state = ctx->state;

    switch (state) {

    case sw_start:
        if (p[0] != '2' || p[1] != '2' || p[2] != '0') {
            return NGX_ERROR;
        }

        b->last = ngx_slprintf(b->pos, b->end, "HELO %V" CRLF, &ctx->u.host);

        state = sw_helo;
        break;

    case sw_helo:
        if (p[0] != '2' || p[1] != '5' || p[2] != '0') {
            return NGX_ERROR;
        }

        b->last = ngx_cpymem(b->pos, "AUTH LOGIN" CRLF,
                             sizeof("AUTH LOGIN" CRLF) - 1);

        state = sw_login;
        break;

    case sw_login:
        if (p[0] != '3' || p[1] != '3' || p[2] != '4') {
            return NGX_ERROR;
        }

        src = ctx->user;

        dst.len = ngx_base64_encoded_length(src.len);
        dst.data = ngx_pnalloc(ctx->pool, dst.len);
        if (dst.data == NULL) {
            return NGX_ERROR;
        }

        ngx_encode_base64(&dst, &src);

        b->last = ngx_slprintf(b->pos, b->end, "%V" CRLF, &dst);

        state = sw_user;
        break;

    case sw_user:
        if (p[0] != '3' || p[1] != '3' || p[2] != '4') {
            return NGX_ERROR;
        }

        src = ctx->passwd;

        dst.len = ngx_base64_encoded_length(src.len);
        dst.data = ngx_pnalloc(ctx->pool, dst.len);
        if (dst.data == NULL) {
            return NGX_ERROR;
        }

        ngx_encode_base64(&dst, &src);

        b->last = ngx_slprintf(b->pos, b->end, "%V" CRLF, &dst);

        state = sw_passwd;
        break;

    case sw_passwd:
        if (p[0] != '2' || p[1] != '3' || p[2] != '5') {
            return NGX_ERROR;
        }

        b->last = ngx_slprintf(b->pos, b->end, "MAIL FROM:<%V>" CRLF,
                               &ctx->from);

        state = sw_from;
        break;

    case sw_from:
        if (p[0] != '2' || p[1] != '5' || p[2] != '0') {
            return NGX_ERROR;
        }

        to = ctx->to.elts;
        b->last = ngx_slprintf(b->pos, b->end, "RCPT TO:<%V>" CRLF,
                               &to[ctx->n++]);

        state = sw_to;
        break;

    case sw_to:
        if (p[0] != '2' || p[1] != '5' || p[2] != '0') {
            return NGX_ERROR;
        }

        if (ctx->n < ctx->to.nelts) {
            to = ctx->to.elts;
            b->last = ngx_slprintf(b->pos, b->end, "RCPT TO:<%V>" CRLF,
                                   &to[ctx->n++]);
            break;
        }

        b->last = ngx_cpymem(b->pos, "DATA" CRLF, sizeof("DATA" CRLF) - 1);

        state = sw_data;
        break;

    case sw_data:
        if (p[0] != '3' || p[1] != '5' || p[2] != '4') {
            return NGX_ERROR;
        }

        b->last = ngx_slprintf(b->pos, b->end, "Subject: %V" CRLF,
                               &ctx->subject);

        to = ctx->to.elts;
        for (i = 0; i < ctx->to.nelts; i++) {
            b->last = ngx_slprintf(b->last, b->end, "To: %V" CRLF, &to[i]);
        }

        b->last = ngx_slprintf(b->last, b->end, CRLF "%V" CRLF "." CRLF,
                               &ctx->content);

        state = sw_quit;
        break;

    case sw_quit:
        if (p[0] != '2' || p[1] != '5' || p[2] != '0') {
            return NGX_ERROR;
        }

        b->last = ngx_cpymem(b->pos, "QUIT" CRLF, sizeof("QUIT" CRLF) - 1);

        state = sw_done;
        break;

    case sw_done:
        if (p[0] != '2' || p[1] != '2' || p[2] != '1') {
            return NGX_ERROR;
        }

        return NGX_DONE;

    default:
        return NGX_ERROR;
    }

    ctx->state = state;

    ctx->peer.connection->read->handler = ngx_lua_smtp_dummy_handler;
    ctx->peer.connection->write->handler = ngx_lua_smtp_write_handler;

    ngx_lua_smtp_write_handler(ctx->peer.connection->write);

    return NGX_OK;
}
static char *ngx_http_acme_sign_json(ngx_conf_t *cf, void *conf, json_t *payload, RSA *key, ngx_str_t replay_nonce, json_t **flattened_jws)
{
    /*
     * Structure according to RFC7515:
     *
     * {
     *  "payload":"<payload contents>",
     *  "protected":"<integrity-protected header contents>",
     *  "header":<non-integrity-protected header contents>,
     *  "signature":"<signature contents>"
     * }
     *
     * Example:
     *
     * {
     *  "payload":
     *   "eyJpc3MiOiJqb2UiLA0KICJleHAiOjEzMDA4MTkzODAsDQogImh0dHA6Ly9leGFtcGxlLmNvbS9pc19yb290Ijp0cnVlfQ",
     *  "protected":"eyJhbGciOiJFUzI1NiJ9",
     *  "header": {"kid":"e9bc097a-ce51-4036-9562-d2ade882db0d"},
     *  "signature":
     *   "DtEhU3ljbEg8L38VWAfUAqOyKAM6-Xx-F4GawxaepmXFCgfTjDxw5djxLa8ISlSApmWQxfKTUJqPP3-Kg6NU1Q"
     * }
     */

    /*
     * ACME restrictions:
     * The JWS MUST use the Flattened JSON Serialization
     * The JWS MUST be encoded using UTF-8
     * The JWS Header or Protected Header MUST include “alg” and “jwk” fields
     * The JWS MUST NOT have the value “none” in its “alg” field
     */

    json_t *jwk;
    json_t *header;
    ngx_str_t encoded_protected_header, serialized_payload, encoded_payload, tmp;
    ngx_str_t signing_input, signature, encoded_signature;
    u_char *tmp_char_p;

    /* Variables for signing */
    EVP_PKEY *evp_key;
    EVP_MD_CTX *mdctx = NULL;
    int ret = 0;

    /*
     * Encode payload
     */

    serialized_payload = (ngx_str_t)ngx_string_dynamic(json_dumps(payload, 0));
    encoded_payload.len = ngx_base64_encoded_length(serialized_payload.len);
    encoded_payload.data = ngx_alloc(encoded_payload.len, cf->log);
    ngx_encode_base64url(&encoded_payload, &serialized_payload);

    println_debug("Signing payload: ", &serialized_payload);

    /*
     * Create header
     */

    /* jwk header */
    if(ngx_http_acme_create_jwk(cf, conf, key, &jwk) != NGX_CONF_OK) {
        ngx_log_error(NGX_LOG_ERR, cf->log, 0, "Failed to create the JWK from the account key");
        ngx_free(serialized_payload.data);
        ngx_free(encoded_payload.data);
        return NGX_CONF_ERROR;
    }

    /* Pack header into JSON */
    header = json_pack("{s:s, s:s%, s:o}", "alg", "RS256", "nonce", replay_nonce.data, replay_nonce.len, "jwk", jwk);
    if(header == NULL) {
        ngx_log_error(NGX_LOG_ERR, cf->log, 0, "Error packing JWS header");
        ngx_free(serialized_payload.data);
        ngx_free(encoded_payload.data);
        return NGX_CONF_ERROR;
    }

    /* Serialize and base64url encode header */
    tmp = (ngx_str_t)ngx_string_dynamic(json_dumps(header, 0));
    encoded_protected_header.len = ngx_base64_encoded_length(tmp.len);
    encoded_protected_header.data = ngx_alloc(encoded_protected_header.len, cf->log);
    ngx_encode_base64url(&encoded_protected_header, &tmp);
    ngx_free(tmp.data);
    json_decref(header);

    /*
     * Create signature
     */

    /* Create signing input */
    /* = ASCII(BASE64URL(UTF8(JWS Protected Header)) || '.' || BASE64URL(JWS Payload)) */
    signing_input.len = encoded_protected_header.len + strlen(".") + encoded_payload.len;
    signing_input.data = ngx_alloc(signing_input.len, cf->log);
    tmp_char_p = ngx_copy(signing_input.data, encoded_protected_header.data, encoded_protected_header.len);
    tmp_char_p = ngx_copy(tmp_char_p, ".", strlen("."));
    tmp_char_p = ngx_copy(tmp_char_p, encoded_payload.data, encoded_payload.len);

    /* Convert the RSA key to the EVP_PKEY structure */
    evp_key = EVP_PKEY_new();
    if(evp_key == NULL) {
        ngx_log_error(NGX_LOG_ERR, cf->log, 0,
                "Error signing the message digest for the JWS signature.");
        return NGX_CONF_ERROR;
    }

    if(EVP_PKEY_set1_RSA(evp_key, key) == 0) {
        ngx_log_error(NGX_LOG_ERR, cf->log, 0,
                "Error signing the message digest for the JWS signature.");
        return NGX_CONF_ERROR;
    }

    /* Create the message digest context */
    ret = 0;
    mdctx = EVP_MD_CTX_create();
    if(mdctx == NULL)
        goto err;

    /* Initialize the DigestSign operation - SHA-256 has been selected as the message digest function */
    if(EVP_DigestSignInit(mdctx, NULL, EVP_sha256(), NULL, evp_key) != 1)
        goto err;

    /* Call update with the message */
    if(EVP_DigestSignUpdate(mdctx, signing_input.data, signing_input.len) != 1)
        goto err;

    /* Finalise the DigestSign operation */
    /* First call EVP_DigestSignFinal with a NULL sig parameter to obtain the length of the */
    /* signature. The length is returned in siglen. */
    if(EVP_DigestSignFinal(mdctx, NULL, &signature.len) != 1)
        goto err;

    /* Allocate memory for the signature */
    signature.data = ngx_alloc(signature.len, cf->log);

    /* Obtain the signature */
    if(EVP_DigestSignFinal(mdctx, signature.data, &signature.len) != 1)
        goto err;

    /* Success */
    ret = 1;

    err:
    if(ret != 1) {
        ngx_log_error(NGX_LOG_ERR, cf->log, 0,
                "Error signing the message digest for the JWS signature. OpenSSL error 0x%xl", ERR_get_error());
        return NGX_CONF_ERROR;
    }

    /* Clean up */
    EVP_MD_CTX_destroy(mdctx);
    EVP_PKEY_free(evp_key);

    /* base64url encode the signature */
    encoded_signature.len = ngx_base64_encoded_length(signature.len);
    encoded_signature.data = ngx_alloc(encoded_signature.len, cf->log);
    ngx_encode_base64url(&encoded_signature, &signature);
    ngx_free(signature.data);

    /*
     * Create flattened JWS serialization
     */

    *flattened_jws = json_pack("{s:s%,s:s%,s:s%}",
            "payload", encoded_payload.data, encoded_payload.len,
            "protected", encoded_protected_header.data, encoded_protected_header.len,
            "signature", encoded_signature.data, encoded_signature.len
            );

    ngx_free(serialized_payload.data);
    // TODO (KK) Maybe this is too early for a free since the strings will be used in the flattened JWS (but when to free then?)
    ngx_free(encoded_payload.data);
    ngx_free(encoded_protected_header.data);
    ngx_free(encoded_signature.data);

    if(*flattened_jws == NULL) {
        ngx_log_error(NGX_LOG_ERR, cf->log, 0, "Error serializing flattened JWS");
        return NGX_CONF_ERROR;
    }


    return NGX_CONF_OK;
} /* ngx_http_acme_sign_json */
static ngx_int_t
ngx_ssl_ocsp_create_request(ngx_ssl_ocsp_ctx_t *ctx)
{
    int            len;
    u_char        *p;
    uintptr_t      escape;
    ngx_str_t      binary, base64;
    ngx_buf_t     *b;
    OCSP_CERTID   *id;
    OCSP_REQUEST  *ocsp;

    ocsp = OCSP_REQUEST_new();
    if (ocsp == NULL) {
        ngx_ssl_error(NGX_LOG_CRIT, ctx->log, 0,
                      "OCSP_REQUEST_new() failed");
        return NGX_ERROR;
    }

    id = OCSP_cert_to_id(NULL, ctx->cert, ctx->issuer);
    if (id == NULL) {
        ngx_ssl_error(NGX_LOG_CRIT, ctx->log, 0,
                      "OCSP_cert_to_id() failed");
        goto failed;
    }

    if (OCSP_request_add0_id(ocsp, id) == NULL) {
        ngx_ssl_error(NGX_LOG_CRIT, ctx->log, 0,
                      "OCSP_request_add0_id() failed");
        OCSP_CERTID_free(id);
        goto failed;
    }

    len = i2d_OCSP_REQUEST(ocsp, NULL);
    if (len <= 0) {
        ngx_ssl_error(NGX_LOG_CRIT, ctx->log, 0,
                      "i2d_OCSP_REQUEST() failed");
        goto failed;
    }

    binary.len = len;
    binary.data = ngx_palloc(ctx->pool, len);
    if (binary.data == NULL) {
        goto failed;
    }

    p = binary.data;
    len = i2d_OCSP_REQUEST(ocsp, &p);
    if (len <= 0) {
        ngx_ssl_error(NGX_LOG_EMERG, ctx->log, 0,
                      "i2d_OCSP_REQUEST() failed");
        goto failed;
    }

    base64.len = ngx_base64_encoded_length(binary.len);
    base64.data = ngx_palloc(ctx->pool, base64.len);
    if (base64.data == NULL) {
        goto failed;
    }

    ngx_encode_base64(&base64, &binary);

    escape = ngx_escape_uri(NULL, base64.data, base64.len,
                            NGX_ESCAPE_URI_COMPONENT);

    ngx_log_debug2(NGX_LOG_DEBUG_EVENT, ctx->log, 0,
                   "ssl ocsp request length %z, escape %d",
                   base64.len, (int) escape);

    len = sizeof("GET ") - 1 + ctx->uri.len + sizeof("/") - 1
          + base64.len + 2 * escape + sizeof(" HTTP/1.0" CRLF) - 1
          + sizeof("Host: ") - 1 + ctx->host.len + sizeof(CRLF) - 1
          + sizeof(CRLF) - 1;

    b = ngx_create_temp_buf(ctx->pool, len);
    if (b == NULL) {
        goto failed;
    }

    p = b->last;

    p = ngx_cpymem(p, "GET ", sizeof("GET ") - 1);
    p = ngx_cpymem(p, ctx->uri.data, ctx->uri.len);

    if (ctx->uri.data[ctx->uri.len - 1] != '/') {
        *p++ = '/';
    }

    if (escape == 0) {
        p = ngx_cpymem(p, base64.data, base64.len);

    } else {
        p = (u_char *) ngx_escape_uri(p, base64.data, base64.len,
                                      NGX_ESCAPE_URI_COMPONENT);
    }

    p = ngx_cpymem(p, " HTTP/1.0" CRLF, sizeof(" HTTP/1.0" CRLF) - 1);
    p = ngx_cpymem(p, "Host: ", sizeof("Host: ") - 1);
    p = ngx_cpymem(p, ctx->host.data, ctx->host.len);
    *p++ = CR; *p++ = LF;

    /* add "\r\n" at the header end */
    *p++ = CR; *p++ = LF;

    b->last = p;
    ctx->request = b;

    OCSP_REQUEST_free(ocsp);

    return NGX_OK;

failed:

    OCSP_REQUEST_free(ocsp);

    return NGX_ERROR;
}
static ngx_int_t
ngx_secure_token_cht_get_var(
	ngx_http_request_t *r,
	ngx_http_variable_value_t *v,
	uintptr_t data)
{
	ngx_secure_token_cht_token_t* token = (void*)data;
	ngx_str_t expires_str;
	ngx_str_t md5hash_str;
	ngx_str_t token_str;
	ngx_str_t acl;
	ngx_md5_t md5;
	u_char end_time_buf[NGX_INT32_LEN];
	u_char md5hash_buf[MD5_DIGEST_LENGTH];
	u_char token_buf[ngx_base64_encoded_length(MD5_DIGEST_LENGTH)];
	time_t end_time;
	size_t result_size;
	u_char* p;
	ngx_int_t rc;

	// get the acl
	rc = ngx_http_secure_token_get_acl(r, token->acl, &acl);
	if (rc != NGX_OK)
	{
		return rc;
	}

	// get the end time
	end_time = token->end.val;
	if (token->end.type == NGX_HTTP_SECURE_TOKEN_TIME_RELATIVE)
	{
		end_time += ngx_time();
	}
	expires_str.data = end_time_buf;
	expires_str.len = ngx_sprintf(end_time_buf, "%uD", (uint32_t)end_time) - end_time_buf;
	
	// calculate the signature
	ngx_md5_init(&md5);
	ngx_md5_update(&md5, acl.data, acl.len);
	ngx_md5_update(&md5, token->key.data, token->key.len);
	ngx_md5_update(&md5, expires_str.data, expires_str.len);
	ngx_md5_final(md5hash_buf, &md5);

	md5hash_str.data = md5hash_buf;
	md5hash_str.len = sizeof(md5hash_buf);

	token_str.data = token_buf;
	ngx_encode_base64url(&token_str, &md5hash_str);

	// get the result size
	result_size = sizeof(TOKEN_PART1) + token_str.len + sizeof(TOKEN_PART2) + expires_str.len;

	// allocate the result
	p = ngx_pnalloc(r->pool, result_size);
	if (p == NULL)
	{
		return NGX_ERROR;
	}

	v->data = p;

	// build the result
	p = ngx_copy(p, TOKEN_PART1, sizeof(TOKEN_PART1) - 1);
	p = ngx_copy(p, token_str.data, token_str.len);
	p = ngx_copy(p, TOKEN_PART2, sizeof(TOKEN_PART2) - 1);
	p = ngx_copy(p, expires_str.data, expires_str.len);
	*p = '\0';

	v->len = p - v->data;
	v->valid = 1;
	v->no_cacheable = 0;
	v->not_found = 0;

	return NGX_OK;
}