Initial import.
diff --git a/src/core/security/credentials.c b/src/core/security/credentials.c
new file mode 100644
index 0000000..969a973
--- /dev/null
+++ b/src/core/security/credentials.c
@@ -0,0 +1,534 @@
+/*
+ *
+ * Copyright 2014, Google Inc.
+ * All rights reserved.
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions are
+ * met:
+ *
+ *     * Redistributions of source code must retain the above copyright
+ * notice, this list of conditions and the following disclaimer.
+ *     * Redistributions in binary form must reproduce the above
+ * copyright notice, this list of conditions and the following disclaimer
+ * in the documentation and/or other materials provided with the
+ * distribution.
+ *     * Neither the name of Google Inc. nor the names of its
+ * contributors may be used to endorse or promote products derived from
+ * this software without specific prior written permission.
+ *
+ * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
+ * "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
+ * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
+ * A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT
+ * OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
+ * SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
+ * LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
+ * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
+ * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
+ * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
+ * OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+ *
+ */
+
+#include "src/core/security/credentials.h"
+
+#include "src/core/httpcli/httpcli.h"
+#include "src/core/surface/surface_em.h"
+#include <grpc/support/alloc.h>
+#include <grpc/support/log.h>
+#include <grpc/support/string.h>
+#include <grpc/support/sync.h>
+#include <grpc/support/time.h>
+
+#include "third_party/cJSON/cJSON.h"
+
+#include <string.h>
+#include <stdio.h>
+
+/* -- Constants. -- */
+
+#define GRPC_COMPUTE_ENGINE_TOKEN_REFRESH_THRESHOLD_SECS 60
+#define GRPC_COMPUTE_ENGINE_METADATA_HOST "metadata"
+#define GRPC_COMPUTE_ENGINE_METADATA_TOKEN_PATH \
+  "computeMetadata/v1/instance/service-accounts/default/token"
+#define GRPC_AUTHORIZATION_METADATA_KEY "Authorization"
+
+/* -- Common. -- */
+
+typedef struct {
+  grpc_credentials *creds;
+  grpc_credentials_metadata_cb cb;
+  void *user_data;
+} grpc_credentials_metadata_request;
+
+static grpc_credentials_metadata_request *
+grpc_credentials_metadata_request_create(grpc_credentials *creds,
+                                         grpc_credentials_metadata_cb cb,
+                                         void *user_data) {
+  grpc_credentials_metadata_request *r =
+      gpr_malloc(sizeof(grpc_credentials_metadata_request));
+  r->creds = grpc_credentials_ref(creds);
+  r->cb = cb;
+  r->user_data = user_data;
+  return r;
+}
+
+static void grpc_credentials_metadata_request_destroy(
+    grpc_credentials_metadata_request *r) {
+  grpc_credentials_unref(r->creds);
+  gpr_free(r);
+}
+
+grpc_credentials *grpc_credentials_ref(grpc_credentials *creds) {
+  if (creds == NULL) return NULL;
+  gpr_ref(&creds->refcount);
+  return creds;
+}
+
+void grpc_credentials_unref(grpc_credentials *creds) {
+  if (creds == NULL) return;
+  if (gpr_unref(&creds->refcount)) creds->vtable->destroy(creds);
+}
+
+void grpc_credentials_release(grpc_credentials *creds) {
+  grpc_credentials_unref(creds);
+}
+
+int grpc_credentials_has_request_metadata(grpc_credentials *creds) {
+  if (creds == NULL) return 0;
+  return creds->vtable->has_request_metadata(creds);
+}
+
+int grpc_credentials_has_request_metadata_only(grpc_credentials *creds) {
+  if (creds == NULL) return 0;
+  return creds->vtable->has_request_metadata_only(creds);
+}
+
+void grpc_credentials_get_request_metadata(grpc_credentials *creds,
+                                           grpc_credentials_metadata_cb cb,
+                                           void *user_data) {
+  if (creds == NULL || !grpc_credentials_has_request_metadata(creds)) return;
+  creds->vtable->get_request_metadata(creds, cb, user_data);
+}
+
+void grpc_server_credentials_release(grpc_server_credentials *creds) {
+  if (creds == NULL) return;
+  creds->vtable->destroy(creds);
+}
+
+/* -- Ssl credentials. -- */
+
+typedef struct {
+  grpc_credentials base;
+  grpc_ssl_config config;
+} grpc_ssl_credentials;
+
+typedef struct {
+  grpc_server_credentials base;
+  grpc_ssl_config config;
+} grpc_ssl_server_credentials;
+
+static void ssl_destroy(grpc_credentials *creds) {
+  grpc_ssl_credentials *c = (grpc_ssl_credentials *)creds;
+  if (c->config.pem_root_certs != NULL) gpr_free(c->config.pem_root_certs);
+  if (c->config.pem_private_key != NULL) gpr_free(c->config.pem_private_key);
+  if (c->config.pem_cert_chain != NULL) gpr_free(c->config.pem_cert_chain);
+  gpr_free(creds);
+}
+
+static void ssl_server_destroy(grpc_server_credentials *creds) {
+  grpc_ssl_server_credentials *c = (grpc_ssl_server_credentials *)creds;
+  if (c->config.pem_root_certs != NULL) gpr_free(c->config.pem_root_certs);
+  if (c->config.pem_private_key != NULL) gpr_free(c->config.pem_private_key);
+  if (c->config.pem_cert_chain != NULL) gpr_free(c->config.pem_cert_chain);
+  gpr_free(creds);
+}
+
+static int ssl_has_request_metadata(const grpc_credentials *creds) { return 0; }
+
+static int ssl_has_request_metadata_only(const grpc_credentials *creds) {
+  return 0;
+}
+
+static grpc_credentials_vtable ssl_vtable = {
+    ssl_destroy, ssl_has_request_metadata, ssl_has_request_metadata_only, NULL};
+
+static grpc_server_credentials_vtable ssl_server_vtable = {ssl_server_destroy};
+
+const grpc_ssl_config *grpc_ssl_credentials_get_config(
+    const grpc_credentials *creds) {
+  if (creds == NULL || strcmp(creds->type, GRPC_CREDENTIALS_TYPE_SSL)) {
+    return NULL;
+  } else {
+    grpc_ssl_credentials *c = (grpc_ssl_credentials *)creds;
+    return &c->config;
+  }
+}
+
+const grpc_ssl_config *grpc_ssl_server_credentials_get_config(
+    const grpc_server_credentials *creds) {
+  if (creds == NULL || strcmp(creds->type, GRPC_CREDENTIALS_TYPE_SSL)) {
+    return NULL;
+  } else {
+    grpc_ssl_server_credentials *c = (grpc_ssl_server_credentials *)creds;
+    return &c->config;
+  }
+}
+
+static void ssl_build_config(const unsigned char *pem_root_certs,
+                             size_t pem_root_certs_size,
+                             const unsigned char *pem_private_key,
+                             size_t pem_private_key_size,
+                             const unsigned char *pem_cert_chain,
+                             size_t pem_cert_chain_size,
+                             grpc_ssl_config *config) {
+  if (pem_root_certs != NULL) {
+    config->pem_root_certs = gpr_malloc(pem_root_certs_size);
+    memcpy(config->pem_root_certs, pem_root_certs, pem_root_certs_size);
+    config->pem_root_certs_size = pem_root_certs_size;
+  }
+  if (pem_private_key != NULL) {
+    config->pem_private_key = gpr_malloc(pem_private_key_size);
+    memcpy(config->pem_private_key, pem_private_key, pem_private_key_size);
+    config->pem_private_key_size = pem_private_key_size;
+  }
+  if (pem_cert_chain != NULL) {
+    config->pem_cert_chain = gpr_malloc(pem_cert_chain_size);
+    memcpy(config->pem_cert_chain, pem_cert_chain, pem_cert_chain_size);
+    config->pem_cert_chain_size = pem_cert_chain_size;
+  }
+}
+
+grpc_credentials *grpc_ssl_credentials_create(
+    const unsigned char *pem_root_certs, size_t pem_root_certs_size,
+    const unsigned char *pem_private_key, size_t pem_private_key_size,
+    const unsigned char *pem_cert_chain, size_t pem_cert_chain_size) {
+  grpc_ssl_credentials *c = gpr_malloc(sizeof(grpc_ssl_credentials));
+  memset(c, 0, sizeof(grpc_ssl_credentials));
+  c->base.type = GRPC_CREDENTIALS_TYPE_SSL;
+  c->base.vtable = &ssl_vtable;
+  gpr_ref_init(&c->base.refcount, 1);
+  ssl_build_config(pem_root_certs, pem_root_certs_size, pem_private_key,
+                   pem_private_key_size, pem_cert_chain, pem_cert_chain_size,
+                   &c->config);
+  return &c->base;
+}
+
+grpc_server_credentials *grpc_ssl_server_credentials_create(
+    const unsigned char *pem_root_certs, size_t pem_root_certs_size,
+    const unsigned char *pem_private_key, size_t pem_private_key_size,
+    const unsigned char *pem_cert_chain, size_t pem_cert_chain_size) {
+  grpc_ssl_server_credentials *c =
+      gpr_malloc(sizeof(grpc_ssl_server_credentials));
+  memset(c, 0, sizeof(grpc_ssl_server_credentials));
+  c->base.type = GRPC_CREDENTIALS_TYPE_SSL;
+  c->base.vtable = &ssl_server_vtable;
+  ssl_build_config(pem_root_certs, pem_root_certs_size, pem_private_key,
+                   pem_private_key_size, pem_cert_chain, pem_cert_chain_size,
+                   &c->config);
+  return &c->base;
+}
+
+/* -- ComputeEngine credentials. -- */
+
+typedef struct {
+  grpc_credentials base;
+  gpr_mu mu;
+  grpc_mdctx *md_ctx;
+  grpc_mdelem *access_token_md;
+  gpr_timespec token_expiration;
+} grpc_compute_engine_credentials;
+
+static void compute_engine_destroy(grpc_credentials *creds) {
+  grpc_compute_engine_credentials *c = (grpc_compute_engine_credentials *)creds;
+  if (c->access_token_md != NULL) {
+    grpc_mdelem_unref(c->access_token_md);
+  }
+  gpr_mu_destroy(&c->mu);
+  grpc_mdctx_orphan(c->md_ctx);
+  gpr_free(c);
+}
+
+static int compute_engine_has_request_metadata(const grpc_credentials *creds) {
+  return 1;
+}
+
+static int compute_engine_has_request_metadata_only(
+    const grpc_credentials *creds) {
+  return 1;
+}
+
+grpc_credentials_status grpc_compute_engine_credentials_parse_server_response(
+    const grpc_httpcli_response *response, grpc_mdctx *ctx,
+    grpc_mdelem **token_elem, gpr_timespec *token_lifetime) {
+  char *null_terminated_body = NULL;
+  char *new_access_token = NULL;
+  grpc_credentials_status status = GRPC_CREDENTIALS_OK;
+  cJSON *json = NULL;
+
+  if (response->status != 200) {
+    gpr_log(GPR_ERROR, "Call to metadata server ended with error %d",
+            response->status);
+    status = GRPC_CREDENTIALS_ERROR;
+    goto end;
+  } else {
+    cJSON *access_token = NULL;
+    cJSON *token_type = NULL;
+    cJSON *expires_in = NULL;
+    size_t new_access_token_size = 0;
+    null_terminated_body = gpr_malloc(response->body_length + 1);
+    null_terminated_body[response->body_length] = '\0';
+    memcpy(null_terminated_body, response->body, response->body_length);
+    json = cJSON_Parse(null_terminated_body);
+    if (json == NULL) {
+      gpr_log(GPR_ERROR, "Could not parse JSON from %s", null_terminated_body);
+      status = GRPC_CREDENTIALS_ERROR;
+      goto end;
+    }
+    if (json->type != cJSON_Object) {
+      gpr_log(GPR_ERROR, "Response should be a JSON object");
+      status = GRPC_CREDENTIALS_ERROR;
+      goto end;
+    }
+    access_token = cJSON_GetObjectItem(json, "access_token");
+    if (access_token == NULL || access_token->type != cJSON_String) {
+      gpr_log(GPR_ERROR, "Missing or invalid access_token in JSON.");
+      status = GRPC_CREDENTIALS_ERROR;
+      goto end;
+    }
+    token_type = cJSON_GetObjectItem(json, "token_type");
+    if (token_type == NULL || token_type->type != cJSON_String) {
+      gpr_log(GPR_ERROR, "Missing or invalid token_type in JSON.");
+      status = GRPC_CREDENTIALS_ERROR;
+      goto end;
+    }
+    expires_in = cJSON_GetObjectItem(json, "expires_in");
+    if (expires_in == NULL || expires_in->type != cJSON_Number) {
+      gpr_log(GPR_ERROR, "Missing or invalid expires_in in JSON.");
+      status = GRPC_CREDENTIALS_ERROR;
+      goto end;
+    }
+    new_access_token_size = strlen(token_type->valuestring) + 1 +
+                            strlen(access_token->valuestring) + 1;
+    new_access_token = gpr_malloc(new_access_token_size);
+    /* C89 does not have snprintf :(. */
+    sprintf(new_access_token, "%s %s", token_type->valuestring,
+            access_token->valuestring);
+    token_lifetime->tv_sec = expires_in->valueint;
+    token_lifetime->tv_nsec = 0;
+    if (*token_elem != NULL) grpc_mdelem_unref(*token_elem);
+    *token_elem = grpc_mdelem_from_strings(ctx, GRPC_AUTHORIZATION_METADATA_KEY,
+                                           new_access_token);
+    status = GRPC_CREDENTIALS_OK;
+  }
+
+end:
+  if (status != GRPC_CREDENTIALS_OK && (*token_elem != NULL)) {
+    grpc_mdelem_unref(*token_elem);
+    *token_elem = NULL;
+  }
+  if (null_terminated_body != NULL) gpr_free(null_terminated_body);
+  if (new_access_token != NULL) gpr_free(new_access_token);
+  if (json != NULL) cJSON_Delete(json);
+  return status;
+}
+
+static void on_compute_engine_token_response(
+    void *user_data, const grpc_httpcli_response *response) {
+  grpc_credentials_metadata_request *r =
+      (grpc_credentials_metadata_request *)user_data;
+  grpc_compute_engine_credentials *c =
+      (grpc_compute_engine_credentials *)r->creds;
+  gpr_timespec token_lifetime;
+  grpc_credentials_status status;
+
+  gpr_mu_lock(&c->mu);
+  status = grpc_compute_engine_credentials_parse_server_response(
+      response, c->md_ctx, &c->access_token_md, &token_lifetime);
+  if (status == GRPC_CREDENTIALS_OK) {
+    c->token_expiration = gpr_time_add(gpr_now(), token_lifetime);
+    r->cb(r->user_data, &c->access_token_md, 1, status);
+  } else {
+    c->token_expiration = gpr_inf_past;
+    r->cb(r->user_data, NULL, 0, status);
+  }
+  gpr_mu_unlock(&c->mu);
+  grpc_credentials_metadata_request_destroy(r);
+}
+
+static void compute_engine_get_request_metadata(grpc_credentials *creds,
+                                                grpc_credentials_metadata_cb cb,
+                                                void *user_data) {
+  grpc_compute_engine_credentials *c = (grpc_compute_engine_credentials *)creds;
+  gpr_timespec refresh_threshold = {
+      GRPC_COMPUTE_ENGINE_TOKEN_REFRESH_THRESHOLD_SECS, 0};
+
+  gpr_mu_lock(&c->mu);
+  if (c->access_token_md == NULL ||
+      (gpr_time_cmp(gpr_time_sub(gpr_now(), c->token_expiration),
+                    refresh_threshold) < 0)) {
+    grpc_httpcli_header header = {"Metadata-Flavor", "Google"};
+    grpc_httpcli_request request;
+    request.host = GRPC_COMPUTE_ENGINE_METADATA_HOST;
+    request.path = GRPC_COMPUTE_ENGINE_METADATA_TOKEN_PATH;
+    request.hdr_count = 1;
+    request.hdrs = &header;
+    grpc_httpcli_get(
+        &request, gpr_time_add(gpr_now(), refresh_threshold), grpc_surface_em(),
+        on_compute_engine_token_response,
+        grpc_credentials_metadata_request_create(creds, cb, user_data));
+  } else {
+    cb(user_data, &c->access_token_md, 1, GRPC_CREDENTIALS_OK);
+  }
+  gpr_mu_unlock(&c->mu);
+}
+
+static grpc_credentials_vtable compute_engine_vtable = {
+    compute_engine_destroy, compute_engine_has_request_metadata,
+    compute_engine_has_request_metadata_only,
+    compute_engine_get_request_metadata};
+
+grpc_credentials *grpc_compute_engine_credentials_create(void) {
+  grpc_compute_engine_credentials *c =
+      gpr_malloc(sizeof(grpc_compute_engine_credentials));
+  memset(c, 0, sizeof(grpc_compute_engine_credentials));
+  c->base.type = GRPC_CREDENTIALS_TYPE_OAUTH2;
+  c->base.vtable = &compute_engine_vtable;
+  gpr_ref_init(&c->base.refcount, 1);
+  gpr_mu_init(&c->mu);
+  c->md_ctx = grpc_mdctx_create();
+  c->token_expiration = gpr_inf_past;
+  return &c->base;
+}
+
+/* -- Fake Oauth2 credentials. -- */
+
+typedef struct {
+  grpc_credentials base;
+  grpc_mdctx *md_ctx;
+  grpc_mdelem *access_token_md;
+  int is_async;
+} grpc_fake_oauth2_credentials;
+
+static void fake_oauth2_destroy(grpc_credentials *creds) {
+  grpc_fake_oauth2_credentials *c = (grpc_fake_oauth2_credentials *)creds;
+  if (c->access_token_md != NULL) {
+    grpc_mdelem_unref(c->access_token_md);
+  }
+  grpc_mdctx_orphan(c->md_ctx);
+  gpr_free(c);
+}
+
+static int fake_oauth2_has_request_metadata(const grpc_credentials *creds) {
+  return 1;
+}
+
+static int fake_oauth2_has_request_metadata_only(
+    const grpc_credentials *creds) {
+  return 1;
+}
+
+void on_simulated_token_fetch_done(void *user_data, grpc_em_cb_status status) {
+  grpc_credentials_metadata_request *r =
+      (grpc_credentials_metadata_request *)user_data;
+  grpc_fake_oauth2_credentials *c = (grpc_fake_oauth2_credentials *)r->creds;
+  GPR_ASSERT(status == GRPC_CALLBACK_SUCCESS);
+  r->cb(r->user_data, &c->access_token_md, 1, GRPC_CREDENTIALS_OK);
+  grpc_credentials_metadata_request_destroy(r);
+}
+
+static void fake_oauth2_get_request_metadata(grpc_credentials *creds,
+                                             grpc_credentials_metadata_cb cb,
+                                             void *user_data) {
+  grpc_fake_oauth2_credentials *c = (grpc_fake_oauth2_credentials *)creds;
+
+  if (c->is_async) {
+    GPR_ASSERT(grpc_em_add_callback(grpc_surface_em(),
+                                    on_simulated_token_fetch_done,
+                                    grpc_credentials_metadata_request_create(
+                                        creds, cb, user_data)) == GRPC_EM_OK);
+  } else {
+    cb(user_data, &c->access_token_md, 1, GRPC_CREDENTIALS_OK);
+  }
+}
+
+static grpc_credentials_vtable fake_oauth2_vtable = {
+    fake_oauth2_destroy, fake_oauth2_has_request_metadata,
+    fake_oauth2_has_request_metadata_only, fake_oauth2_get_request_metadata};
+
+grpc_credentials *grpc_fake_oauth2_credentials_create(
+    const char *token_md_value, int is_async) {
+  grpc_fake_oauth2_credentials *c =
+      gpr_malloc(sizeof(grpc_fake_oauth2_credentials));
+  memset(c, 0, sizeof(grpc_fake_oauth2_credentials));
+  c->base.type = GRPC_CREDENTIALS_TYPE_OAUTH2;
+  c->base.vtable = &fake_oauth2_vtable;
+  gpr_ref_init(&c->base.refcount, 1);
+  c->md_ctx = grpc_mdctx_create();
+  c->access_token_md = grpc_mdelem_from_strings(
+      c->md_ctx, GRPC_AUTHORIZATION_METADATA_KEY, token_md_value);
+  c->is_async = is_async;
+  return &c->base;
+}
+
+/* -- Fake transport security credentials. -- */
+
+static void fake_transport_security_credentials_destroy(
+    grpc_credentials *creds) {
+  gpr_free(creds);
+}
+
+static void fake_transport_security_server_credentials_destroy(
+    grpc_server_credentials *creds) {
+  gpr_free(creds);
+}
+
+static int fake_transport_security_has_request_metadata(
+    const grpc_credentials *creds) {
+  return 0;
+}
+
+static int fake_transport_security_has_request_metadata_only(
+    const grpc_credentials *creds) {
+  return 0;
+}
+
+static grpc_credentials_vtable fake_transport_security_credentials_vtable = {
+    fake_transport_security_credentials_destroy,
+    fake_transport_security_has_request_metadata,
+    fake_transport_security_has_request_metadata_only, NULL};
+
+static grpc_server_credentials_vtable
+    fake_transport_security_server_credentials_vtable = {
+        fake_transport_security_server_credentials_destroy};
+
+grpc_credentials *grpc_fake_transport_security_credentials_create(void) {
+  grpc_credentials *c = gpr_malloc(sizeof(grpc_credentials));
+  memset(c, 0, sizeof(grpc_credentials));
+  c->type = GRPC_CREDENTIALS_TYPE_FAKE_TRANSPORT_SECURITY;
+  c->vtable = &fake_transport_security_credentials_vtable;
+  gpr_ref_init(&c->refcount, 1);
+  return c;
+}
+
+grpc_server_credentials *
+grpc_fake_transport_security_server_credentials_create() {
+  grpc_server_credentials *c = gpr_malloc(sizeof(grpc_server_credentials));
+  memset(c, 0, sizeof(grpc_server_credentials));
+  c->type = GRPC_CREDENTIALS_TYPE_FAKE_TRANSPORT_SECURITY;
+  c->vtable = &fake_transport_security_server_credentials_vtable;
+  return c;
+}
+
+
+/* -- Composite credentials TODO(jboeuf). -- */
+
+grpc_credentials *grpc_composite_credentials_create(grpc_credentials *creds1,
+                                                    grpc_credentials *creds2) {
+  return NULL;
+}
+
+/* -- Default credentials TODO(jboeuf). -- */
+
+grpc_credentials *grpc_default_credentials_create(void) { return NULL; }