Пример #1
0
/****************************************************************************
 **                                                                        **
 ** Name:    lowerlayer_data_req()                                     **
 **                                                                        **
 ** Description: Notify the EPS Mobility Management entity that data have  **
 **      to be transfered to lower layers                          **
 **                                                                        **
 ** Inputs:  ueid:      UE lower layer identifier                  **
 **          data:      Data to be transfered to lower layers      **
 **      Others:    None                                       **
 **                                                                        **
 ** Outputs:     None                                                      **
 **      Return:    RETURNok, RETURNerror                      **
 **      Others:    None                                       **
 **                                                                        **
 ***************************************************************************/
int lowerlayer_data_req(unsigned int ueid, const OctetString *data)
{
  LOG_FUNC_IN;

  int rc;
  emm_sap_t emm_sap;
  emm_security_context_t    *sctx = NULL;
  struct emm_data_context_s *ctx  = NULL;

  emm_sap.primitive = EMMAS_DATA_REQ;
  emm_sap.u.emm_as.u.data.guti = _emm_data.guti;
  emm_sap.u.emm_as.u.data.ueid = 0;
  sctx = _emm_data.security;

  emm_sap.u.emm_as.u.data.NASinfo = 0;
  emm_sap.u.emm_as.u.data.NASmsg.length = data->length;
  emm_sap.u.emm_as.u.data.NASmsg.value = data->value;
  /* Setup EPS NAS security data */
  emm_as_set_security_data(&emm_sap.u.emm_as.u.data.sctx, sctx, FALSE, TRUE);
  rc = emm_sap_send(&emm_sap);

  LOG_FUNC_RETURN (rc);
}
Пример #2
0
static int
sc_single_transmit(struct sc_card *card, struct sc_apdu *apdu)
{
	struct sc_context *ctx  = card->ctx;
	int rv;

	LOG_FUNC_CALLED(ctx);
	if (card->reader->ops->transmit == NULL)
		LOG_TEST_RET(card->ctx, SC_ERROR_NOT_SUPPORTED, "cannot transmit APDU");

	sc_log(ctx, "CLA:%X, INS:%X, P1:%X, P2:%X, data(%i) %p",
			apdu->cla, apdu->ins, apdu->p1, apdu->p2, apdu->datalen, apdu->data);
#ifdef ENABLE_SM
	if (card->sm_ctx.sm_mode == SM_MODE_TRANSMIT)
		return sc_sm_single_transmit(card, apdu);
#endif

	/* send APDU to the reader driver */
	rv = card->reader->ops->transmit(card->reader, apdu);
	LOG_TEST_RET(ctx, rv, "unable to transmit APDU");

	LOG_FUNC_RETURN(ctx, rv);
}
Пример #3
0
static int esteid_select(struct sc_card *card, unsigned char p1, unsigned char id1, unsigned char id2) {
	struct sc_apdu apdu;
	unsigned char sbuf[2];

	LOG_FUNC_CALLED(card->ctx);

	// Select EF/DF
	sbuf[0] = id1;
	sbuf[1] = id2;

	sc_format_apdu(card, &apdu, SC_APDU_CASE_1, 0xA4, p1, 0x0C);
	if (id1 != 0x3F && id2 != 0x00) {
		apdu.cse = SC_APDU_CASE_3_SHORT;
		apdu.lc = 2;
		apdu.data = sbuf;
		apdu.datalen = 2;
	}
	apdu.le = 0;
	apdu.resplen = 0;

	SC_TRANSMIT_TEST_RET(card, apdu, "SELECT failed");
	LOG_FUNC_RETURN(card->ctx, SC_SUCCESS);
}
Пример #4
0
/****************************************************************************
 **                                                                        **
 ** Name:    _emm_attach_t3410_handler()                               **
 **                                                                        **
 ** Description: T3410 timeout handler                                     **
 **                                                                        **
 **              3GPP TS 24.301, section 5.5.1.2.6, case c                 **
 **      Upon T3410 timer expiration, the attach procedure shall   **
 **      be aborted and the UE shall execute abnormal case attach  **
 **      procedure.                                                **
 **      The NAS signalling connection shall be released locally.  **
 **                                                                        **
 ** Inputs:  args:      handler parameters                         **
 **      Others:    None                                       **
 **                                                                        **
 ** Outputs:     None                                                      **
 **      Return:    None                                       **
 **      Others:    T3410                                      **
 **                                                                        **
 ***************************************************************************/
void *_emm_attach_t3410_handler(void *args)
{
  LOG_FUNC_IN;

  emm_sap_t emm_sap;
  int rc;

  LOG_TRACE(WARNING, "EMM-PROC  - T3410 timer expired");

  /* Stop T3410 timer */
  T3410.id = nas_timer_stop(T3410.id);
  /* Execute abnormal case attach procedure */
  _emm_attach_abnormal_cases_bcd(&emm_sap);

  rc = emm_sap_send(&emm_sap);

  if (rc != RETURNerror) {
    /* Locally release the NAS signalling connection */
    _emm_data.ecm_status = ECM_IDLE;
  }

  LOG_FUNC_RETURN(NULL);
}
static int
myeid_init_card(sc_profile_t *profile,
		sc_pkcs15_card_t *p15card) {
	struct sc_path path;
	struct sc_file *file = NULL;
        u8 rbuf[256];
	int r;

	LOG_FUNC_CALLED(p15card->card->ctx);

	p15card->tokeninfo->flags = SC_PKCS15_TOKEN_PRN_GENERATION | SC_PKCS15_TOKEN_EID_COMPLIANT;

        r = sc_card_ctl(p15card->card, SC_CARDCTL_GET_SERIALNR, &rbuf);
	LOG_TEST_RET(p15card->card->ctx, r,  "Get applet info failed");

        sc_format_path("3F00", &path);
	r = sc_select_file(p15card->card, &path, &file);

	if (file)
		sc_file_free(file);

	LOG_FUNC_RETURN(p15card->card->ctx, r);
}
Пример #6
0
/****************************************************************************
 **                                                                        **
 ** Name:    _emm_attach_t3402_handler()                               **
 **                                                                        **
 ** Description: T3402 timeout handler                                     **
 **                                                                        **
 **      Upon T3402 timer expiration:                              **
 **              3GPP TS 24.301, section 5.5.1.1                           **
 **      the attach attempt counter shall be reset when the UE is  **
 **      in substate DEREGISTERED.ATTEMPTING-TO-ATTACH;            **
 **              3GPP TS 24.301, section 5.2.2.3.3                         **
 **      the UE shall initiate an attach or combined attach proce- **
 **      dure in substate DEREGISTERED.ATTEMPTING-TO-ATTACH;       **
 **                                                                        **
 ** Inputs:  args:      handler parameters                         **
 **      Others:    None                                       **
 **                                                                        **
 ** Outputs:     None                                                      **
 **      Return:    None                                       **
 **      Others:    _emm_attach_data, T3402                    **
 **                                                                        **
 ***************************************************************************/
static void *_emm_attach_t3402_handler(void *args)
{
  LOG_FUNC_IN;

  emm_sap_t emm_sap;

  LOG_TRACE(WARNING, "EMM-PROC  - T3402 timer expired");

  /* Stop T3402 timer */
  T3402.id = nas_timer_stop(T3402.id);
  /* Reset the attach attempt counter */
  _emm_attach_data.attempt_count = 0;
  /*
   * Notify EMM that timer T3402 expired and attach procedure has to be
   * restarted
   */
  emm_sap.primitive = EMMREG_ATTACH_INIT;
  emm_sap.u.emm_reg.u.attach.is_emergency = _emm_data.is_emergency;

  (void) emm_sap_send(&emm_sap);

  LOG_FUNC_RETURN(NULL);
}
Пример #7
0
int
sc_pkcs15_encode_pubkey_dsa(sc_context_t *ctx, struct sc_pkcs15_pubkey_dsa *key,
		u8 **buf, size_t *buflen)
{
	struct sc_asn1_entry asn1_public_key[C_ASN1_PUBLIC_KEY_SIZE];
	struct sc_asn1_entry asn1_dsa_pub_coefficients[C_ASN1_DSA_PUB_COEFFICIENTS_SIZE];
	int r;

	LOG_FUNC_CALLED(ctx);
	sc_copy_asn1_entry(c_asn1_public_key, asn1_public_key);
	sc_copy_asn1_entry(c_asn1_dsa_pub_coefficients, asn1_dsa_pub_coefficients);

	sc_format_asn1_entry(asn1_public_key + 0, asn1_dsa_pub_coefficients, NULL, 1);
	sc_format_asn1_entry(asn1_dsa_pub_coefficients + 0, key->pub.data, &key->pub.len, 1);
	sc_format_asn1_entry(asn1_dsa_pub_coefficients + 1, key->g.data, &key->g.len, 1);
	sc_format_asn1_entry(asn1_dsa_pub_coefficients + 2, key->p.data, &key->p.len, 1);
	sc_format_asn1_entry(asn1_dsa_pub_coefficients + 3, key->q.data, &key->q.len, 1);

	r = sc_asn1_encode(ctx, asn1_public_key, buf, buflen);
	LOG_TEST_RET(ctx, r, "ASN.1 encoding failed");

	LOG_FUNC_RETURN(ctx, SC_SUCCESS);
}
Пример #8
0
/****************************************************************************
 **                                                                        **
 ** Name:  as_message_send()                                         **
 **                                                                        **
 ** Description: Service provided to the EPS Mobility Management protocol  **
 **    at the EMMAS Access Point (EMMAS-SAP) to send AS messages **
 **    to the Access Stratum sublayer.                           **
 **                                                                        **
 ** Inputs:  as_msg:  The AS message to send                     **
 **      Others:  _network_api_send_buffer, _network_api_id  **
 **                                                                        **
 ** Outputs:   Return:  The number of bytes sent when success;     **
 **       RETURNerror Otherwise                      **
 **      Others:  _network_api_send_buffer                   **
 **                                                                        **
 ***************************************************************************/
int as_message_send(as_message_t* as_msg)
{
  int bytes;
  LOG_FUNC_IN;

  LOG_TRACE(INFO, "NET-API   - Send message 0x%.4x to the Access Stratum "
            "layer", as_msg->msgID);

  /* Encode the AS message */
  bytes = network_api_encode_data(as_msg);

  if (bytes > 0) {
    /* Get the network file descriptor */
    int fd = network_api_get_fd();

    if (fd != RETURNerror) {
      /* Send the AS message to the network */
      bytes = network_api_send_data(fd, bytes);
    }
  }

  LOG_FUNC_RETURN (bytes);
}
/****************************************************************************
 **                                                                        **
 ** Name:    emm_recv_security_mode_command()                          **
 **                                                                        **
 ** Description: Processes Security Mode Command message                   **
 **                                                                        **
 ** Inputs:  msg:       The received EMM message                   **
 **      Others:    None                                       **
 **                                                                        **
 ** Outputs:     emm_cause: EMM cause code                             **
 **      Return:    RETURNok, RETURNerror                      **
 **      Others:    None                                       **
 **                                                                        **
 ***************************************************************************/
int emm_recv_security_mode_command(security_mode_command_msg *msg,
                                   int *emm_cause)
{
  LOG_FUNC_IN;

  int rc;

  LOG_TRACE(INFO, "EMMAS-SAP - Received Security Mode Command message");

  /*
   * Message processing
   */
  /* Execute the security mode control procedure initiated by the network */
  rc = emm_proc_security_mode_command(
         msg->naskeysetidentifier.tsc != NAS_KEY_SET_IDENTIFIER_MAPPED,
         msg->naskeysetidentifier.naskeysetidentifier,
         msg->selectednassecurityalgorithms.typeofcipheringalgorithm,
         msg->selectednassecurityalgorithms.typeofintegrityalgorithm,
         msg->replayeduesecuritycapabilities.eea,
         msg->replayeduesecuritycapabilities.eia);

  LOG_FUNC_RETURN (rc);
}
Пример #10
0
static int
iasecc_sm_get_challenge(struct sc_card *card, unsigned char *out, size_t len)
{
	struct sc_context *ctx = card->ctx;
	struct sc_apdu apdu;
	unsigned char rbuf[SC_MAX_APDU_BUFFER_SIZE];
	int rv;

	sc_log(ctx, "SM get challenge: length %i",len);
	sc_format_apdu(card, &apdu, SC_APDU_CASE_2_SHORT, 0x84, 0, 0);
	apdu.le = len;
	apdu.resplen = len;
	apdu.resp = rbuf;

	rv = sc_transmit_apdu(card, &apdu);
	LOG_TEST_RET(ctx, rv, "APDU transmit failed");
	rv = sc_check_sw(card, apdu.sw1, apdu.sw2);
	LOG_TEST_RET(ctx, rv, "Command failed");

	memcpy(out, rbuf, apdu.resplen);

	LOG_FUNC_RETURN(ctx, apdu.resplen);
}
Пример #11
0
/**
 * Retrieve Root CA public key.
 *
 * Just returns (as local SM authentication) static data
 * @param card Pointer to card driver structure
 * @param root_ca_key pointer to resulting returned key
 * @return SC_SUCCESS if ok; else error code
 */
static int dnie_get_root_ca_pubkey(sc_card_t * card, EVP_PKEY ** root_ca_key)
{
	int res=SC_SUCCESS;
	RSA *root_ca_rsa=NULL;
	BIGNUM *root_ca_rsa_n, *root_ca_rsa_e;
	LOG_FUNC_CALLED(card->ctx);

	/* compose root_ca_public key with data provided by Dnie Manual */
	*root_ca_key = EVP_PKEY_new();
	root_ca_rsa = RSA_new();
	if (!*root_ca_key || !root_ca_rsa) {
		sc_log(card->ctx, "Cannot create data for root CA public key");
		return SC_ERROR_OUT_OF_MEMORY;
	}

	root_ca_rsa_n = BN_bin2bn(icc_root_ca_modulus, sizeof(icc_root_ca_modulus), NULL);
	root_ca_rsa_e = BN_bin2bn(icc_root_ca_public_exponent, sizeof(icc_root_ca_public_exponent), NULL);
	if (RSA_set0_key(root_ca_rsa, root_ca_rsa_n, root_ca_rsa_e, NULL) != 1) {
		BN_free(root_ca_rsa_n);
		BN_free(root_ca_rsa_e);
		if (*root_ca_key)
			EVP_PKEY_free(*root_ca_key);
		if (root_ca_rsa)
			RSA_free(root_ca_rsa);
		sc_log(card->ctx, "Cannot set RSA valuses for CA public key");
		return SC_ERROR_INTERNAL;
	}

	res = EVP_PKEY_assign_RSA(*root_ca_key, root_ca_rsa);
	if (!res) {
		if (*root_ca_key)
			EVP_PKEY_free(*root_ca_key);	/*implies root_ca_rsa free() */
		sc_log(card->ctx, "Cannot compose root CA public key");
		return SC_ERROR_INTERNAL;
	}
	LOG_FUNC_RETURN(card->ctx, SC_SUCCESS);
}
Пример #12
0
static int sc_hsm_update_ef(sc_pkcs15_card_t *p15card, u8 prefix, u8 id, int erase, u8 *buf, size_t buflen)
{
	sc_card_t *card = p15card->card;
	sc_file_t *file = NULL;
	sc_file_t newfile;
	sc_path_t path;
	u8 fid[2];
	int r;

	fid[0] = prefix;
	fid[1] = id;

	sc_path_set(&path, SC_PATH_TYPE_FILE_ID, fid, 2, 0, -1);

	r = sc_select_file(card, &path, NULL);

	if ((r == SC_SUCCESS) && erase) {
		r = sc_delete_file(card, &path);
		LOG_TEST_RET(card->ctx, r, "Could not delete file");
		r = SC_ERROR_FILE_NOT_FOUND;
	}

	if (r == SC_ERROR_FILE_NOT_FOUND) {
		file = sc_file_new();
		file->id = (path.value[0] << 8) | path.value[1];
		file->type = SC_FILE_TYPE_WORKING_EF;
		file->ef_structure = SC_FILE_EF_TRANSPARENT;
		file->size = (size_t) 0;
		file->status = SC_FILE_STATUS_ACTIVATED;
		r = sc_create_file(card, file);
		sc_file_free(file);
		LOG_TEST_RET(card->ctx, r, "Could not create file");
	}

	r = sc_update_binary(card, 0, buf, buflen, 0);
	LOG_FUNC_RETURN(card->ctx, r);
}
/****************************************************************************
 **                                                                        **
 ** Name:    _authentication_t3460_handler()                           **
 **                                                                        **
 ** Description: T3460 timeout handler                                     **
 **      Upon T3460 timer expiration, the authentication request   **
 **      message is retransmitted and the timer restarted. When    **
 **      retransmission counter is exceed, the MME shall abort the **
 **      authentication procedure and any ongoing EMM specific     **
 **      procedure and release the NAS signalling connection.      **
 **                                                                        **
 **              3GPP TS 24.301, section 5.4.2.7, case b                   **
 **                                                                        **
 ** Inputs:  args:      handler parameters                         **
 **      Others:    None                                       **
 **                                                                        **
 ** Outputs:     None                                                      **
 **      Return:    None                                       **
 **      Others:    None                                       **
 **                                                                        **
 ***************************************************************************/
static void *_authentication_t3460_handler(void *args)
{
  LOG_FUNC_IN;

  int rc;

  authentication_data_t *data = (authentication_data_t *)(args);

  /* Increment the retransmission counter */
  data->retransmission_count += 1;

  LOG_TRACE(WARNING, "EMM-PROC  - T3460 timer expired, retransmission "
            "counter = %d", data->retransmission_count);

  if (data->retransmission_count < AUTHENTICATION_COUNTER_MAX) {
    /* Send authentication request message to the UE */
    rc = _authentication_request(data);
  } else {
    unsigned int ueid = data->ueid;
    /* Set the failure notification indicator */
    data->notify_failure = TRUE;
    /* Abort the authentication procedure */
    rc = _authentication_abort(data);

    /* Release the NAS signalling connection */
    if (rc != RETURNerror) {
      emm_sap_t emm_sap;
      emm_sap.primitive = EMMAS_RELEASE_REQ;
      emm_sap.u.emm_as.u.release.guti = NULL;
      emm_sap.u.emm_as.u.release.ueid = ueid;
      emm_sap.u.emm_as.u.release.cause = EMM_AS_CAUSE_AUTHENTICATION;
      rc = emm_sap_send(&emm_sap);
    }
  }

  LOG_FUNC_RETURN (NULL);
}
Пример #14
0
/****************************************************************************
 **                                                                        **
 ** Name:    emm_send_security_mode_command()                          **
 **                                                                        **
 ** Description: Builds Security Mode Command message                      **
 **                                                                        **
 **      The Security Mode Command message is sent by the network  **
 **      to the UE to establish NAS signalling security.           **
 **                                                                        **
 ** Inputs:  msg:       The EMMAS-SAP primitive to process         **
 **      Others:    None                                       **
 **                                                                        **
 ** Outputs:     emm_msg:   The EMM message to be sent                 **
 **      Return:    The size of the EMM message                **
 **      Others:    None                                       **
 **                                                                        **
 ***************************************************************************/
int emm_send_security_mode_command(const emm_as_security_t *msg,
                                   security_mode_command_msg *emm_msg)
{
  LOG_FUNC_IN;

  int size = EMM_HEADER_MAXIMUM_LENGTH;

  LOG_TRACE(INFO, "EMMAS-SAP - Send Security Mode Command message");

  /* Mandatory - Message type */
  emm_msg->messagetype = SECURITY_MODE_COMMAND;

  /* Selected NAS security algorithms */
  size += NAS_SECURITY_ALGORITHMS_MAXIMUM_LENGTH;
  emm_msg->selectednassecurityalgorithms.typeofcipheringalgorithm =
    msg->selected_eea;
  emm_msg->selectednassecurityalgorithms.typeofintegrityalgorithm =
    msg->selected_eia;

  /* NAS key set identifier */
  size += NAS_KEY_SET_IDENTIFIER_MAXIMUM_LENGTH;
  emm_msg->naskeysetidentifier.tsc = NAS_KEY_SET_IDENTIFIER_NATIVE;
  emm_msg->naskeysetidentifier.naskeysetidentifier = msg->ksi;

  /* Replayed UE security capabilities */
  size += UE_SECURITY_CAPABILITY_MAXIMUM_LENGTH;
  emm_msg->replayeduesecuritycapabilities.eea = msg->eea;
  emm_msg->replayeduesecuritycapabilities.eia = msg->eia;
  emm_msg->replayeduesecuritycapabilities.umts_present = msg->umts_present;
  emm_msg->replayeduesecuritycapabilities.gprs_present = msg->gprs_present;

  emm_msg->replayeduesecuritycapabilities.uea = msg->uea;
  emm_msg->replayeduesecuritycapabilities.uia = msg->uia;
  emm_msg->replayeduesecuritycapabilities.gea = msg->gea;

  LOG_FUNC_RETURN (size);
}
/****************************************************************************
 **                                                                        **
 ** Name:    _eps_bearer_deactivate_t3495_handler()                    **
 **                                                                        **
 ** Description: T3495 timeout handler                                     **
 **                                                                        **
 **              3GPP TS 24.301, section 6.4.4.5, case a                   **
 **      On the first expiry of the timer T3495, the MME shall re- **
 **      send the DEACTIVATE EPS BEARER CONTEXT REQUEST and shall  **
 **      reset and restart timer T3495. This retransmission is     **
 **      repeated four times, i.e. on the fifth expiry of timer    **
 **      T3495, the MME shall abort the procedure and deactivate   **
 **      the EPS bearer context locally.                           **
 **                                                                        **
 ** Inputs:  args:      handler parameters                         **
 **      Others:    None                                       **
 **                                                                        **
 ** Outputs:     None                                                      **
 **      Return:    None                                       **
 **      Others:    None                                       **
 **                                                                        **
 ***************************************************************************/
static void *_eps_bearer_deactivate_t3495_handler(void *args)
{
  LOG_FUNC_IN;

  int rc;

  /* Get retransmission timer parameters data */
  esm_ebr_timer_data_t *data = (esm_ebr_timer_data_t *)(args);

  /* Increment the retransmission counter */
  data->count += 1;

  LOG_TRACE(WARNING, "ESM-PROC  - T3495 timer expired (ueid="NAS_UE_ID_FMT", ebi=%d), "
            "retransmission counter = %d",
            data->ueid, data->ebi, data->count);

  if (data->count < EPS_BEARER_DEACTIVATE_COUNTER_MAX) {
    /* Re-send deactivate EPS bearer context request message to the UE */
    rc = _eps_bearer_deactivate(data->ctx, data->ebi, &data->msg);
  } else {
    /*
     * The maximum number of deactivate EPS bearer context request
     * message retransmission has exceed
     */
    int pid, bid;
    /* Deactivate the EPS bearer context locally without peer-to-peer
     * signalling between the UE and the MME */
    rc = _eps_bearer_release(data->ctx, data->ebi, &pid, &bid);

    if (rc != RETURNerror) {
      /* Stop timer T3495 */
      rc = esm_ebr_stop_timer(data->ctx, data->ebi);
    }
  }

  LOG_FUNC_RETURN (NULL);
}
Пример #16
0
static int
iso7816_update_record(struct sc_card *card, unsigned int rec_nr,
		const u8 *buf, size_t count, unsigned long flags)
{
	struct sc_apdu apdu;
	int r;

	sc_format_apdu(card, &apdu, SC_APDU_CASE_3, 0xDC, rec_nr, 0);
	apdu.p2 = (flags & SC_RECORD_EF_ID_MASK) << 3;
	if (flags & SC_RECORD_BY_REC_NR)
		apdu.p2 |= 0x04;

	apdu.lc = count;
	apdu.datalen = count;
	apdu.data = buf;

	fixup_transceive_length(card, &apdu);
	r = sc_transmit_apdu(card, &apdu);
	LOG_TEST_RET(card->ctx, r, "APDU transmit failed");
	r = sc_check_sw(card, apdu.sw1, apdu.sw2);
	LOG_TEST_RET(card->ctx, r, "Card returned error");

	LOG_FUNC_RETURN(card->ctx, count);
}
Пример #17
0
int
iasecc_sm_update_binary(struct sc_card *card, unsigned se_num, size_t offs,
		const unsigned char *buff, size_t count)
{
	struct sc_context *ctx = card->ctx;
#ifdef ENABLE_SM
	struct sm_info *sm_info = &card->sm_ctx.info;
	struct sc_remote_data rdata;
	struct iasecc_sm_cmd_update_binary cmd_data;
	int rv;

	LOG_FUNC_CALLED(ctx);
	sc_log(ctx, "SM update binary: acl:%X, offs:%i, count:%i", se_num, offs, count);

	rv = iasecc_sm_initialize(card, se_num, SM_CMD_FILE_UPDATE);
	LOG_TEST_RET(ctx, rv, "iasecc_sm_update_binary() SM INITIALIZE failed");

	cmd_data.offs = offs;
	cmd_data.count = count;
	cmd_data.data = buff;
	sm_info->cmd_data = &cmd_data;

	sc_remote_data_init(&rdata);
	rv = iasecc_sm_cmd(card, &rdata);
	LOG_TEST_RET(ctx, rv, "iasecc_sm_update_binary() SM 'UPDATE BINARY' failed");

	rv = sm_release (card, &rdata, NULL, 0);
	LOG_TEST_RET(ctx, rv, "iasecc_sm_update_binary() SM release failed");

	rdata.free(&rdata);
	LOG_FUNC_RETURN(ctx, count);
#else
	LOG_TEST_RET(ctx, SC_ERROR_NOT_SUPPORTED, "built without support of Secure-Messaging");
	return SC_ERROR_NOT_SUPPORTED;
#endif
}
Пример #18
0
/****************************************************************************
 **                                                                        **
 ** Name:    _emm_detach_abort()                                       **
 **                                                                        **
 ** Description: Aborts the detach procedure                               **
 **                                                                        **
 ** Inputs:  type:      not used                                   **
 **      Others:    _emm_detach_data                           **
 **                                                                        **
 ** Outputs:     None                                                      **
 **      Return:    RETURNok, RETURNerror                      **
 **      Others:    T3421                                      **
 **                                                                        **
 ***************************************************************************/
static int _emm_detach_abort(emm_proc_detach_type_t type)
{
  LOG_FUNC_IN;

  emm_sap_t emm_sap;
  int rc ;

  LOG_TRACE(WARNING, "EMM-PROC  - Abort the detach procedure");

  /* Reset EMM procedure handler */
  (void) emm_proc_lowerlayer_initialize(NULL, NULL, NULL, NULL);

  /* Stop timer T3421 */
  T3421.id = nas_timer_stop(T3421.id);

  /*
   * Notify EMM that detach procedure failed
   */
  emm_sap.primitive = EMMREG_DETACH_FAILED;
  emm_sap.u.emm_reg.u.detach.type = type;
  rc = emm_sap_send(&emm_sap);

  LOG_FUNC_RETURN (rc);
}
Пример #19
0
/****************************************************************************
 **                                                                        **
 ** Name:	 user_api_decode_data()                                    **
 **                                                                        **
 ** Description: Parses the message received from the user application     **
 **		 (mainly AT commands) and fills the user data structure.   **
 **		 Returns an AT syntax error code to the user application   **
 **		 layer when the AT command failed to be decoded.           **
 **                                                                        **
 ** Inputs:	 length:	Number of bytes to decode                  **
 ** 	 	 Others:	_user_api_recv_buffer                      **
 **                                                                        **
 ** Outputs:	 Return:	The number of AT commands succeessfully    **
 **				decoded                                    **
 ** 	 	 Others:	_user_api_send_buffer, _user_data          **
 **                                                                        **
 ***************************************************************************/
int user_api_decode_data(int length)
{
    LOG_FUNC_IN;

    /* Parse the AT command line */
    LOG_TRACE(INFO, "USR-API   - Decode user data: %s", _user_api_recv_buffer);
    _user_data.n_cmd = at_command_decode(_user_api_recv_buffer, length,
                                         _user_data.cmd);

    if (_user_data.n_cmd > 0) {
        /* AT command data received from the user application layer
         * has been successfully decoded */
        LOG_TRACE(INFO, "USR-API   - %d AT command%s ha%s been successfully "
                  "decoded", _user_data.n_cmd,
                  (_user_data.n_cmd > 1) ? "s" : "",
                  (_user_data.n_cmd > 1) ? "ve" : "s");
    }
    else
    {
        int bytes;

        /* Failed to decode AT command data received from the user
         * application layer; Return syntax error code message */
        LOG_TRACE(ERROR, "USR-API   - Syntax error: Failed to decode "
                  "AT command data %s", _user_api_recv_buffer);

        /* Encode the syntax error code message	*/
        bytes = at_error_encode(_user_api_send_buffer, AT_ERROR_SYNTAX,
                                AT_ERROR_OPERATION_NOT_SUPPORTED);

        /* Send the syntax error code message	*/
        (void) _user_api_send_data(bytes);
    }

    LOG_FUNC_RETURN (_user_data.n_cmd);
}
Пример #20
0
/****************************************************************************
 **                                                                        **
 ** Name:    emm_proc_detach_failure()                                 **
 **                                                                        **
 ** Description: Performs the detach procedure abnormal case upon receipt  **
 **          of transmission failure of Detach Request message.        **
 **                                                                        **
 **              3GPP TS 24.301, section 5.5.2.2.4, case h                 **
 **      The UE shall restart the detach procedure.                **
 **                                                                        **
 ** Inputs:  is_initial:    Not used                                   **
 **          args:      Not used                                   **
 **      Others:    _emm_detach_data                           **
 **                                                                        **
 ** Outputs:     None                                                      **
 **      Return:    RETURNok, RETURNerror                      **
 **      Others:    None                                       **
 **                                                                        **
 ***************************************************************************/
int emm_proc_detach_failure(int is_initial, void *args)
{
  LOG_FUNC_IN;

  emm_sap_t emm_sap;
  int rc;

  LOG_TRACE(WARNING, "EMM-PROC  - Network detach failure");

  /* Reset EMM procedure handler */
  (void) emm_proc_lowerlayer_initialize(NULL, NULL, NULL, NULL);

  /* Stop timer T3421 */
  T3421.id = nas_timer_stop(T3421.id);

  /*
   * Notify EMM that detach procedure has to be restarted
   */
  emm_sap.primitive = EMMREG_DETACH_INIT;
  emm_sap.u.emm_reg.u.detach.switch_off = _emm_detach_data.switch_off;
  rc = emm_sap_send(&emm_sap);

  LOG_FUNC_RETURN(rc);
}
static int sc_pkcs15emu_sc_hsm_read_tokeninfo (sc_pkcs15_card_t * p15card)
{
    sc_card_t *card = p15card->card;
    sc_file_t *file = NULL;
    sc_path_t path;
    int r;
    u8 efbin[512];

    LOG_FUNC_CALLED(card->ctx);

    /* Read token info */
    sc_path_set(&path, SC_PATH_TYPE_FILE_ID, (u8 *) "\x2F\x03", 2, 0, 0);
    r = sc_select_file(card, &path, &file);
    LOG_TEST_RET(card->ctx, r, "Could not select EF.TokenInfo");
    sc_file_free(file);

    r = sc_read_binary(p15card->card, 0, efbin, sizeof(efbin), 0);
    LOG_TEST_RET(card->ctx, r, "Could not read EF.TokenInfo");

    r = sc_pkcs15_parse_tokeninfo(card->ctx, p15card->tokeninfo, efbin, r);
    LOG_TEST_RET(card->ctx, r, "Could not decode EF.TokenInfo");

    LOG_FUNC_RETURN(card->ctx, SC_SUCCESS);
}
Пример #22
0
/*
 * Select the PIN reference
 */
static int
myeid_select_pin_reference(sc_profile_t *profile, sc_pkcs15_card_t *p15card,
		sc_pkcs15_auth_info_t *auth_info) {
	SC_FUNC_CALLED(p15card->card->ctx, SC_LOG_DEBUG_VERBOSE);

	if (auth_info->auth_type != SC_PKCS15_PIN_AUTH_TYPE_PIN)
		return SC_ERROR_OBJECT_NOT_VALID;

	if (auth_info->attrs.pin.flags & SC_PKCS15_PIN_FLAG_SO_PIN) {
		sc_log(p15card->card->ctx,
				"PIN_FLAG_SO_PIN, ref (%d), tries_left (%d)",
				auth_info->attrs.pin.reference, auth_info->tries_left);
	} else {
		sc_log(p15card->card->ctx,
				"PIN_FLAG_PIN, ref (%d), tries_left (%d)",
				auth_info->attrs.pin.reference, auth_info->tries_left);

	}

	if (auth_info->attrs.pin.reference <= 0 || auth_info->attrs.pin.reference > MYEID_MAX_PINS)
		auth_info->attrs.pin.reference = 1;

	LOG_FUNC_RETURN(p15card->card->ctx, SC_SUCCESS);
}
Пример #23
0
/****************************************************************************
 **                                                                        **
 ** Name:    esm_proc_status()                                         **
 **                                                                        **
 ** Description: Initiates ESM status procedure.                           **
 **                                                                        **
 ** Inputs:  is_standalone: Not used - Always TRUE                     **
 **      ueid:      UE lower layer identifier                  **
 **      ebi:       Not used                                   **
 **      msg:       Encoded ESM status message to be sent      **
 **      ue_triggered:  Not used                                   **
 **      Others:    None                                       **
 **                                                                        **
 ** Outputs:     None                                                      **
 **      Return:    RETURNok, RETURNerror                      **
 **      Others:    None                                       **
 **                                                                        **
 ***************************************************************************/
int
esm_proc_status (
  int is_standalone,
  emm_data_context_t * ctx,
  int ebi,
  OctetString * msg,
  int ue_triggered)
{
  LOG_FUNC_IN;
  int                                     rc;
  emm_sap_t                               emm_sap;

  LOG_TRACE (INFO, "ESM-PROC  - ESM status procedure requested");
  /*
   * Notity EMM that ESM PDU has to be forwarded to lower layers
   */
  emm_sap.primitive = EMMESM_UNITDATA_REQ;
  emm_sap.u.emm_esm.ueid = ctx->ueid;
  emm_sap.u.emm_esm.ctx = ctx;
  emm_sap.u.emm_esm.u.data.msg.length = msg->length;
  emm_sap.u.emm_esm.u.data.msg.value = msg->value;
  rc = emm_sap_send (&emm_sap);
  LOG_FUNC_RETURN (rc);
}
Пример #24
0
int
iasecc_sm_create_file(struct sc_card *card, unsigned se_num, unsigned char *fcp, size_t fcp_len)
{
	struct sc_context *ctx = card->ctx;
#ifdef ENABLE_SM
	struct sm_info *sm_info = &card->sm_ctx.info;
	struct sc_remote_data rdata;
	struct iasecc_sm_cmd_create_file cmd_data;
	int rv;

	LOG_FUNC_CALLED(ctx);
	sc_log(ctx,
	       "iasecc_sm_create_file() SE#%i, fcp(%"SC_FORMAT_LEN_SIZE_T"u) '%s'",
	       se_num, fcp_len, sc_dump_hex(fcp, fcp_len));

	rv = iasecc_sm_initialize(card, se_num, SM_CMD_FILE_CREATE);
	LOG_TEST_RET(ctx, rv, "iasecc_sm_create_file() SM INITIALIZE failed");

	cmd_data.data = fcp;
	cmd_data.size = fcp_len;
	sm_info->cmd_data = &cmd_data;

	sc_remote_data_init(&rdata);
	rv= iasecc_sm_cmd(card, &rdata);
	LOG_TEST_RET(ctx, rv, "iasecc_sm_create_file() SM 'UPDATE BINARY' failed");

	rv = sm_release (card, &rdata, NULL, 0);
	LOG_TEST_RET(ctx, rv, "iasecc_sm_create_file() SM release failed");

	rdata.free(&rdata);
	LOG_FUNC_RETURN(ctx, rv);
#else
	LOG_TEST_RET(ctx, SC_ERROR_NOT_SUPPORTED, "built without support of Secure-Messaging");
	return SC_ERROR_NOT_SUPPORTED;
#endif
}
Пример #25
0
static int
iasecc_parse_pubkey(struct sc_card *card, unsigned char *data, size_t data_len, struct iasecc_sdo_pubkey *pubkey)
{
	struct sc_context *ctx = card->ctx;
	size_t offs = 0;
	int rv;

	LOG_FUNC_CALLED(ctx);
	while(offs < data_len)   {
		struct iasecc_extended_tlv tlv;

		rv = iasecc_parse_get_tlv(card, data + offs, &tlv);
		LOG_TEST_RET(ctx, rv, "iasecc_parse_pubkey() get and parse TLV error");

		sc_log(ctx,
		       "iasecc_parse_pubkey() get and parse TLV returned %i; tag %X; size %"SC_FORMAT_LEN_SIZE_T"u",
		       rv, tlv.tag, tlv.size);

		if (tlv.tag == IASECC_SDO_PUBKEY_TAG_N)
			pubkey->n = tlv;
		else if (tlv.tag == IASECC_SDO_PUBKEY_TAG_E)
			pubkey->e = tlv;
		else if (tlv.tag == IASECC_SDO_PUBKEY_TAG_CHR)
			pubkey->chr = tlv;
		else if (tlv.tag == IASECC_SDO_PUBKEY_TAG_CHA)
			pubkey->cha = tlv;
		else if (tlv.tag == IASECC_SDO_PUBKEY_TAG_COMPULSORY)
			pubkey->compulsory = tlv;
		else
			LOG_TEST_RET(ctx, SC_ERROR_UNKNOWN_DATA_RECEIVED, "parse error: non PubKey SDO tag");

		offs += rv;
	}

	LOG_FUNC_RETURN(ctx, SC_SUCCESS);
}
Пример #26
0
int
sm_cwa_decode_authentication_data(struct sc_context *ctx, struct sm_cwa_keyset *keyset,
		struct sm_cwa_session *session_data, unsigned char *auth_data)
{
	DES_cblock icv = {0, 0, 0, 0, 0, 0, 0, 0};
	DES_cblock cblock;
	unsigned char *decrypted = NULL;
	size_t decrypted_len;
	int rv;

	LOG_FUNC_CALLED(ctx);

	memset(icv, 0, sizeof(icv));
	rv = sm_cwa_get_mac(ctx, keyset->mac, &icv, session_data->mdata, 0x40, &cblock, 1);
	LOG_TEST_RET(ctx, rv, "Decode authentication data:  sm_ecc_get_mac failed");
	sc_log(ctx, "MAC:%s", sc_dump_hex(cblock, sizeof(cblock)));

	if(memcmp(session_data->mdata + 0x40, cblock, 8))
		LOG_FUNC_RETURN(ctx, SC_ERROR_SM_AUTHENTICATION_FAILED);

	rv = sm_decrypt_des_cbc3(ctx, keyset->enc, session_data->mdata, session_data->mdata_len, &decrypted, &decrypted_len);
	LOG_TEST_RET(ctx, rv, "sm_ecc_decode_auth_data() DES CBC3 decrypt error");

	sc_log(ctx, "sm_ecc_decode_auth_data() decrypted(%i) %s", decrypted_len, sc_dump_hex(decrypted, decrypted_len));

	if (memcmp(decrypted, session_data->icc.rnd, 8))
		LOG_FUNC_RETURN(ctx, SC_ERROR_UNKNOWN_DATA_RECEIVED);

	if (memcmp(decrypted + 8, session_data->icc.sn, 8))
		LOG_FUNC_RETURN(ctx, SC_ERROR_UNKNOWN_DATA_RECEIVED);

	if (memcmp(decrypted + 16, session_data->ifd.rnd, 8))
		LOG_FUNC_RETURN(ctx, SC_ERROR_UNKNOWN_DATA_RECEIVED);

	if (memcmp(decrypted + 24, session_data->ifd.sn, 8))
		LOG_FUNC_RETURN(ctx, SC_ERROR_UNKNOWN_DATA_RECEIVED);

	memcpy(session_data->icc.k, decrypted + 32, 32);

	free(decrypted);
	LOG_FUNC_RETURN(ctx, SC_SUCCESS);
}
Пример #27
0
int
sm_gp_decode_card_answer(struct sc_context *ctx, struct sc_remote_data *rdata, unsigned char *out, size_t out_len)
{
	LOG_FUNC_RETURN(ctx, SC_ERROR_NOT_SUPPORTED);
}
Пример #28
0
int
sm_gp_external_authentication(struct sc_context *ctx, struct sm_info *sm_info,
		unsigned char *init_data, size_t init_len, struct sc_remote_data *rdata,
		int (*diversify_keyset)(struct sc_context *ctx,
				struct sm_info *sm_info,
				unsigned char *idata, size_t idata_len))
{
	struct sc_remote_apdu *new_rapdu = NULL;
	struct sc_apdu *apdu = NULL;
	unsigned char host_cryptogram[8], raw_apdu[SC_MAX_APDU_BUFFER_SIZE];
	struct sm_gp_session *gp_session = &sm_info->session.gp;
	DES_cblock mac;
	int rv, offs = 0;

	LOG_FUNC_CALLED(ctx);
	if (!sm_info || !init_data || !rdata || !rdata->alloc)
		LOG_FUNC_RETURN(ctx, SC_ERROR_INVALID_ARGUMENTS);

	if (init_len != 0x1C)
		LOG_TEST_RET(ctx, SC_ERROR_UNKNOWN_DATA_RECEIVED, "SM GP authentication: invalid auth data length");

	rv = sm_gp_parse_init_data(ctx, gp_session, init_data, init_len);
	LOG_TEST_RET(ctx, rv, "SM GP authentication: 'INIT DATA' parse error");

	if (diversify_keyset)   {
		rv = (*diversify_keyset)(ctx, sm_info, init_data, init_len);
		LOG_TEST_RET(ctx, rv, "SM GP authentication: keyset diversification error");
	}

	rv = sm_gp_init_session(ctx, gp_session, init_data + 20, 8);
	LOG_TEST_RET(ctx, rv, "SM GP authentication: init session error");

	rv = sm_gp_get_cryptogram(gp_session->session_enc,
			gp_session->card_challenge, gp_session->host_challenge,
			host_cryptogram, sizeof(host_cryptogram));
	LOG_TEST_RET(ctx, rv, "SM GP authentication: get host cryptogram error");

	sc_debug(ctx, SC_LOG_DEBUG_SM, "SM GP authentication: host_cryptogram:%s", sc_dump_hex(host_cryptogram, 8));

	rv = rdata->alloc(rdata, &new_rapdu);
	LOG_TEST_RET(ctx, rv, "SM GP authentication: cannot allocate remote APDU");
	apdu = &new_rapdu->apdu;

	offs = 0;
	apdu->cse = SC_APDU_CASE_3_SHORT;
	apdu->cla = raw_apdu[offs++] = 0x84;
	apdu->ins = raw_apdu[offs++] = 0x82;
	apdu->p1  = raw_apdu[offs++] = gp_session->params.level;
	apdu->p2  = raw_apdu[offs++] = 0;
	apdu->lc  = raw_apdu[offs++] = 0x10;
	apdu->datalen = 0x10;

	memcpy(raw_apdu + offs, host_cryptogram, 8);
	offs += 8;
	rv = sm_gp_get_mac(gp_session->session_mac, &gp_session->mac_icv, raw_apdu, offs, &mac);
	LOG_TEST_RET(ctx, rv, "SM GP authentication: get MAC error");

	memcpy(new_rapdu->sbuf, host_cryptogram, 8);
	memcpy(new_rapdu->sbuf + 8, mac, 8);
	memcpy(gp_session->mac_icv, mac, 8);

	LOG_FUNC_RETURN(ctx, 1);
}
Пример #29
0
int
sm_gp_securize_apdu(struct sc_context *ctx, struct sm_info *sm_info,
		char *init_data, struct sc_apdu *apdu)
{
	unsigned char  buff[SC_MAX_APDU_BUFFER_SIZE + 24];
	unsigned char *apdu_data = NULL;
	struct sm_gp_session *gp_session = &sm_info->session.gp;
	unsigned gp_level = sm_info->session.gp.params.level;
	unsigned gp_index = sm_info->session.gp.params.index;
	DES_cblock mac;
	unsigned char *encrypted = NULL;
	size_t encrypted_len = 0;
	int rv;

	LOG_FUNC_CALLED(ctx);

	apdu_data = (unsigned char *)apdu->data;
	sc_debug(ctx, SC_LOG_DEBUG_SM,
	       "SM GP securize APDU(cse:%X,cla:%X,ins:%X,data(len:%"SC_FORMAT_LEN_SIZE_T"u,%p),lc:%"SC_FORMAT_LEN_SIZE_T"u,GP level:%X,GP index:%X",
	       apdu->cse, apdu->cla, apdu->ins, apdu->datalen, apdu->data,
	       apdu->lc, gp_level, gp_index);

	if (gp_level == 0 || (apdu->cla & 0x04))
		return 0;

	if (gp_level == SM_GP_SECURITY_MAC)   {
		if (apdu->datalen + 8 > SC_MAX_APDU_BUFFER_SIZE)
			LOG_TEST_RET(ctx, SC_ERROR_WRONG_LENGTH, "SM GP securize APDU: too much data");
	}
	else if (gp_level == SM_GP_SECURITY_ENC)   {
		if (!gp_session->session_enc)
			LOG_TEST_RET(ctx, SC_ERROR_SM_INVALID_SESSION_KEY, "SM GP securize APDU: no ENC session key found");

		if (sm_gp_encrypt_command_data(ctx, gp_session->session_enc, apdu->data, apdu->datalen, &encrypted, &encrypted_len))
			LOG_TEST_RET(ctx, SC_ERROR_SM_ENCRYPT_FAILED, "SM GP securize APDU: data encryption error");

		if (encrypted_len + 8 > SC_MAX_APDU_BUFFER_SIZE)
			LOG_TEST_RET(ctx, SC_ERROR_BUFFER_TOO_SMALL, "SM GP securize APDU: not enough place for encrypted data");

		sc_debug(ctx, SC_LOG_DEBUG_SM,
		       "SM GP securize APDU: encrypted length %"SC_FORMAT_LEN_SIZE_T"u",
		       encrypted_len);
	}
	else   {
		LOG_TEST_RET(ctx, SC_ERROR_SM_INVALID_LEVEL, "SM GP securize APDU: invalid SM level");
	}

	buff[0] = apdu->cla | 0x04;
	buff[1] = apdu->ins;
	buff[2] = apdu->p1;
	buff[3] = apdu->p2;
	buff[4] = apdu->lc + 8;

	memcpy(buff + 5, apdu_data, apdu->datalen);

	rv = sm_gp_get_mac(gp_session->session_mac, &gp_session->mac_icv, buff, 5 + apdu->datalen, &mac);
	LOG_TEST_RET(ctx, rv, "SM GP securize APDU: get MAC error");

	if (gp_level == SM_GP_SECURITY_MAC)   {
		memcpy(apdu_data + apdu->datalen, mac, 8);

		apdu->cla |= 0x04;
		apdu->datalen += 8;
		apdu->lc = apdu->datalen;

		if (apdu->cse==SC_APDU_CASE_2_SHORT)
			apdu->cse = SC_APDU_CASE_4_SHORT;
	}
	else if (gp_level == SM_GP_SECURITY_ENC)   {
		memcpy(apdu_data + encrypted_len, mac, 8);
		if (encrypted_len)
			memcpy(apdu_data, encrypted, encrypted_len);

		apdu->cla |= 0x04;
		apdu->datalen = encrypted_len + 8;
		apdu->lc = encrypted_len + 8;

		if (apdu->cse == SC_APDU_CASE_2_SHORT)
			apdu->cse = SC_APDU_CASE_4_SHORT;

		if (apdu->cse == SC_APDU_CASE_1)
			apdu->cse = SC_APDU_CASE_3_SHORT;

		free(encrypted);
	}

	memcpy(sm_info->session.gp.mac_icv, mac, 8);

	LOG_FUNC_RETURN(ctx, rv);
}
Пример #30
0
static int
parse_x509_cert(sc_context_t *ctx, struct sc_pkcs15_der *der, struct sc_pkcs15_cert *cert)
{
    int r;
    struct sc_algorithm_id sig_alg;
    struct sc_pkcs15_pubkey *pubkey = NULL;
    unsigned char *serial = NULL, *issuer = NULL, *subject = NULL, *buf =  der->value;
    size_t serial_len = 0, issuer_len = 0, subject_len = 0, data_len = 0, buflen = der->len;
    struct sc_asn1_entry asn1_version[] = {
        { "version", SC_ASN1_INTEGER, SC_ASN1_TAG_INTEGER, 0, &cert->version, NULL },
        { NULL, 0, 0, 0, NULL, NULL }
    };
    struct sc_asn1_entry asn1_x509v3[] = {
        { "certificatePolicies",	SC_ASN1_OCTET_STRING, SC_ASN1_SEQUENCE | SC_ASN1_CONS, SC_ASN1_OPTIONAL, NULL, NULL },
        { "subjectKeyIdentifier",	SC_ASN1_OCTET_STRING, SC_ASN1_SEQUENCE | SC_ASN1_CONS, SC_ASN1_OPTIONAL, NULL, NULL },
        { "crlDistributionPoints",	SC_ASN1_OCTET_STRING, SC_ASN1_SEQUENCE | SC_ASN1_CONS, SC_ASN1_OPTIONAL | SC_ASN1_ALLOC, &cert->crl, &cert->crl_len },
        { "authorityKeyIdentifier",	SC_ASN1_OCTET_STRING, SC_ASN1_SEQUENCE | SC_ASN1_CONS, SC_ASN1_OPTIONAL, NULL, NULL },
        { "keyUsage",			SC_ASN1_BOOLEAN, SC_ASN1_SEQUENCE | SC_ASN1_CONS, SC_ASN1_OPTIONAL, NULL, NULL },
        { NULL, 0, 0, 0, NULL, NULL }
    };
    struct sc_asn1_entry asn1_extensions[] = {
        { "x509v3",		SC_ASN1_STRUCT,    SC_ASN1_TAG_SEQUENCE | SC_ASN1_CONS, SC_ASN1_OPTIONAL, asn1_x509v3, NULL },
        { NULL, 0, 0, 0, NULL, NULL }
    };
    struct sc_asn1_entry asn1_tbscert[] = {
        { "version",		SC_ASN1_STRUCT,    SC_ASN1_CTX | 0 | SC_ASN1_CONS, SC_ASN1_OPTIONAL, asn1_version, NULL },
        { "serialNumber",	SC_ASN1_OCTET_STRING, SC_ASN1_TAG_INTEGER, SC_ASN1_ALLOC, &serial, &serial_len },
        { "signature",		SC_ASN1_STRUCT,    SC_ASN1_TAG_SEQUENCE | SC_ASN1_CONS, 0, NULL, NULL },
        { "issuer",		SC_ASN1_OCTET_STRING, SC_ASN1_TAG_SEQUENCE | SC_ASN1_CONS, SC_ASN1_ALLOC, &issuer, &issuer_len },
        { "validity",		SC_ASN1_STRUCT,    SC_ASN1_TAG_SEQUENCE | SC_ASN1_CONS, 0, NULL, NULL },
        { "subject",		SC_ASN1_OCTET_STRING, SC_ASN1_TAG_SEQUENCE | SC_ASN1_CONS, SC_ASN1_ALLOC, &subject, &subject_len },
        /* Use a callback to get the algorithm, parameters and pubkey into sc_pkcs15_pubkey */
        { "subjectPublicKeyInfo",SC_ASN1_CALLBACK, SC_ASN1_TAG_SEQUENCE | SC_ASN1_CONS, 0, sc_pkcs15_pubkey_from_spki,  &pubkey },
        { "extensions",		SC_ASN1_STRUCT,    SC_ASN1_CTX | 3 | SC_ASN1_CONS, SC_ASN1_OPTIONAL, asn1_extensions, NULL },
        { NULL, 0, 0, 0, NULL, NULL }
    };
    struct sc_asn1_entry asn1_cert[] = {
        { "tbsCertificate",	SC_ASN1_STRUCT,    SC_ASN1_TAG_SEQUENCE | SC_ASN1_CONS, 0, asn1_tbscert, NULL },
        { "signatureAlgorithm",	SC_ASN1_ALGORITHM_ID, SC_ASN1_TAG_SEQUENCE | SC_ASN1_CONS, 0, &sig_alg, NULL },
        { "signatureValue",	SC_ASN1_BIT_STRING, SC_ASN1_TAG_BIT_STRING, 0, NULL, NULL },
        { NULL, 0, 0, 0, NULL, NULL }
    };
    struct sc_asn1_entry asn1_serial_number[] = {
        { "serialNumber", SC_ASN1_OCTET_STRING, SC_ASN1_TAG_INTEGER, SC_ASN1_ALLOC, NULL, NULL },
        { NULL, 0, 0, 0, NULL, NULL }
    };
    struct sc_asn1_entry asn1_subject[] = {
        { "subject", SC_ASN1_OCTET_STRING, SC_ASN1_TAG_SEQUENCE | SC_ASN1_CONS, SC_ASN1_ALLOC, NULL, NULL },
        { NULL, 0, 0, 0, NULL, NULL }
    };
    struct sc_asn1_entry asn1_issuer[] = {
        { "issuer", SC_ASN1_OCTET_STRING, SC_ASN1_TAG_SEQUENCE | SC_ASN1_CONS, SC_ASN1_ALLOC, NULL, NULL },
        { NULL, 0, 0, 0, NULL, NULL }
    };

    const u8 *obj;
    size_t objlen;

    memset(cert, 0, sizeof(*cert));
    obj = sc_asn1_verify_tag(ctx, buf, buflen, SC_ASN1_TAG_SEQUENCE | SC_ASN1_CONS, &objlen);
    if (obj == NULL)
        LOG_TEST_RET(ctx, SC_ERROR_INVALID_ASN1_OBJECT, "X.509 certificate not found");

    data_len = objlen + (obj - buf);
    cert->data.value = malloc(data_len);
    if (!cert->data.value)
        LOG_FUNC_RETURN(ctx, SC_ERROR_OUT_OF_MEMORY);
    memcpy(cert->data.value, buf, data_len);
    cert->data.len = data_len;

    r = sc_asn1_decode(ctx, asn1_cert, obj, objlen, NULL, NULL);
    LOG_TEST_RET(ctx, r, "ASN.1 parsing of certificate failed");

    cert->version++;

    if (!pubkey)
        LOG_TEST_RET(ctx, SC_ERROR_INVALID_ASN1_OBJECT, "Unable to decode subjectPublicKeyInfo from cert");
    cert->key = pubkey;

    sc_asn1_clear_algorithm_id(&sig_alg);

    if (serial && serial_len)   {
        sc_format_asn1_entry(asn1_serial_number + 0, serial, &serial_len, 1);
        r = sc_asn1_encode(ctx, asn1_serial_number, &cert->serial, &cert->serial_len);
        free(serial);
        LOG_TEST_RET(ctx, r, "ASN.1 encoding of serial failed");
    }

    if (subject && subject_len)   {
        sc_format_asn1_entry(asn1_subject + 0, subject, &subject_len, 1);
        r = sc_asn1_encode(ctx, asn1_subject, &cert->subject, &cert->subject_len);
        free(subject);
        LOG_TEST_RET(ctx, r, "ASN.1 encoding of subject");
    }

    if (issuer && issuer_len)   {
        sc_format_asn1_entry(asn1_issuer + 0, issuer, &issuer_len, 1);
        r = sc_asn1_encode(ctx, asn1_issuer, &cert->issuer, &cert->issuer_len);
        free(issuer);
        LOG_TEST_RET(ctx, r, "ASN.1 encoding of issuer");
    }

    return SC_SUCCESS;
}