static int check_bl3x_key_cert(const unsigned char *buf, size_t len,
			       const unsigned char *i_key, size_t i_key_len,
			       unsigned char *s_key, size_t *s_key_len,
			       const char *key_oid)
{
	const unsigned char *p;
	size_t sz;
	int err, flags;

	x509_crt_init(&cert);

	/* Parse key certificate */
	err = x509_crt_parse(&cert, buf, len);
	if (err) {
		ERROR("Key certificate parse error %d.\n", err);
		goto error;
	}

	/* Verify certificate */
	err = x509_crt_verify(&cert, &cert, NULL, NULL, &flags, NULL, NULL);
	if (err) {
		ERROR("Key certificate verification error %d. Flags: "
				"0x%x.\n", err, flags);
		goto error;
	}

	/* Check that the certificate has been signed by the issuer */
	err = pk_write_pubkey_der(&cert.pk, pk_buf, sizeof(pk_buf));
	if (err < 0) {
		ERROR("Error loading key in DER format %d.\n", err);
		goto error;
	}

	sz = (size_t)err;
	p = pk_buf + sizeof(pk_buf) - sz;
	if ((sz != i_key_len) || memcmp(p, i_key, sz)) {
		ERROR("Key certificate not signed with issuer key\n");
		err = 1;
		goto error;
	}

	/* Get the content certificate key */
	err = x509_get_crt_ext_data(&p, &sz, &cert, key_oid);
	if (err) {
		ERROR("Extension %s not found in Key certificate\n", key_oid);
		goto error;
	}

	assert(sz <= RSA_PUB_DER_MAX_BYTES);
	memcpy(s_key, p, sz);
	*s_key_len = sz;

error:
	x509_crt_free(&cert);

	return err;
}
/*
 * Parse and verify the BL2 certificate
 *
 * This function verifies the integrity of the BL2 certificate, checks that it
 * has been signed with the ROT key and extracts the BL2 hash stored in the
 * certificate so it can be matched later against the calculated hash.
 *
 * Return: 0 = success, Otherwise = error
 */
static int check_bl2_cert(unsigned char *buf, size_t len)
{
	const unsigned char *p;
	size_t sz;
	int err, flags;

	x509_crt_init(&cert);

	/* Parse the BL2 certificate */
	err = x509_crt_parse(&cert, buf, len);
	if (err) {
		ERROR("BL2 certificate parse error %d.\n", err);
		goto error;
	}

	/* Check that it has been signed with the ROT key */
	err = pk_write_pubkey_der(&cert.pk, pk_buf, sizeof(pk_buf));
	if (err < 0) {
		ERROR("Error loading ROT key in DER format %d.\n", err);
		goto error;
	}

	sz = (size_t)err;
	p = pk_buf + sizeof(pk_buf) - sz;

	err = plat_match_rotpk(p, sz);
	if (err) {
		ERROR("ROT and BL2 certificate key mismatch\n");
		goto error;
	}

	/* Verify certificate */
	err = x509_crt_verify(&cert, &cert, NULL, NULL, &flags, NULL, NULL);
	if (err) {
		ERROR("BL2 certificate verification error %d. Flags: 0x%x.\n",
				err, flags);
		goto error;
	}

	/* Extract BL2 image hash from certificate */
	err = x509_get_crt_ext_data(&p, &sz, &cert, BL2_HASH_OID);
	if (err) {
		ERROR("Cannot read BL2 hash from certificate\n");
		goto error;
	}

	assert(sz == SHA_BYTES + 2);

	/* Skip the tag and length bytes and copy the hash */
	p += 2;
	memcpy(sha_bl2, p, SHA_BYTES);

error:
	x509_crt_free(&cert);

	return err;
}
static int check_bl3x_cert(unsigned char *buf, size_t len,
		       const unsigned char *i_key, size_t i_key_len,
		       const char *hash_oid, unsigned char *sha)
{
	const unsigned char *p;
	size_t sz;
	int err, flags;

	x509_crt_init(&cert);

	/* Parse BL31 content certificate */
	err = x509_crt_parse(&cert, buf, len);
	if (err) {
		ERROR("Content certificate parse error %d.\n", err);
		goto error;
	}

	/* Verify certificate */
	err = x509_crt_verify(&cert, &cert, NULL, NULL, &flags, NULL, NULL);
	if (err) {
		ERROR("Content certificate verification error %d. Flags: "
				"0x%x.\n", err, flags);
		goto error;
	}

	/* Check that content certificate has been signed with the content
	 * certificate key corresponding to this image */
	sz = pk_write_pubkey_der(&cert.pk, pk_buf, sizeof(pk_buf));
	p = pk_buf + sizeof(pk_buf) - sz;

	if ((sz != i_key_len) || memcmp(p, i_key, sz)) {
		ERROR("Content certificate not signed with content "
				"certificate key\n");
		err = 1;
		goto error;
	}

	/* Extract image hash from certificate */
	err = x509_get_crt_ext_data(&p, &sz, &cert, hash_oid);
	if (err) {
		ERROR("Cannot read hash from certificate\n");
		goto error;
	}

	assert(sz == SHA_BYTES + 2);

	/* Skip the tag and length bytes and copy the hash */
	p += 2;
	memcpy(sha, p, SHA_BYTES);

error:
	x509_crt_free(&cert);

	return err;
}
Exemple #4
0
AString cRSAPrivateKey::GetPubKeyDER(void)
{
	class cPubKey
	{
	public:
		cPubKey(rsa_context * a_Rsa) :
			m_IsValid(false)
		{
			pk_init(&m_Key);
			if (pk_init_ctx(&m_Key, pk_info_from_type(POLARSSL_PK_RSA)) != 0)
			{
				ASSERT(!"Cannot init PrivKey context");
				return;
			}
			if (rsa_copy(pk_rsa(m_Key), a_Rsa) != 0)
			{
				ASSERT(!"Cannot copy PrivKey to PK context");
				return;
			}
			m_IsValid = true;
		}
		
		~cPubKey()
		{
			if (m_IsValid)
			{
				pk_free(&m_Key);
			}
		}
		
		operator pk_context * (void) { return &m_Key; }
		
	protected:
		bool m_IsValid;
		pk_context m_Key;
	} PkCtx(&m_Rsa);
	
	unsigned char buf[3000];
	int res = pk_write_pubkey_der(PkCtx, buf, sizeof(buf));
	if (res < 0)
	{
		return AString();
	}
	return AString((const char *)(buf + sizeof(buf) - res), (size_t)res);
}
static int write_public_key( pk_context *key, const char *output_file )
{
    int ret;
    FILE *f;
    unsigned char output_buf[16000];
    unsigned char *c = output_buf;
    size_t len = 0;

    memset(output_buf, 0, 16000);

#if defined(POLARSSL_PEM_WRITE_C)
    if( opt.output_format == OUTPUT_FORMAT_PEM )
    {
        if( ( ret = pk_write_pubkey_pem( key, output_buf, 16000 ) ) != 0 )
            return( ret );

        len = strlen( (char *) output_buf );
    }
    else
#endif
    {
        if( ( ret = pk_write_pubkey_der( key, output_buf, 16000 ) ) < 0 )
            return( ret );

        len = ret;
        c = output_buf + sizeof(output_buf) - len - 1;
    }

    if( ( f = fopen( output_file, "w" ) ) == NULL )
        return( -1 );

    if( fwrite( c, 1, len, f ) != len )
    {
        fclose( f );
        return( -1 );
    }

    fclose( f );

    return( 0 );
}
int pk_write_pubkey_pem( pk_context *key, unsigned char *buf, size_t size )
{
    int ret;
    unsigned char output_buf[1280000];
    size_t olen = 0;

    if( ( ret = pk_write_pubkey_der( key, output_buf,
                                     sizeof(output_buf) ) ) < 0 )
    {
        return( ret );
    }

    if( ( ret = pem_write_buffer( PEM_BEGIN_PUBLIC_KEY, PEM_END_PUBLIC_KEY,
                                  output_buf + sizeof(output_buf) - ret,
                                  ret, buf, size, &olen ) ) != 0 )
    {
        return( ret );
    }

    return( 0 );
}
Exemple #7
0
result_t PKey::exportDer(obj_ptr<Buffer_base> &retVal)
{
    result_t hr;
    bool priv;

    hr = isPrivate(priv);
    if (hr < 0)
        return hr;

    int ret;
    std::string buf;

    buf.resize(8192);
    if (priv)
        ret = pk_write_key_der(&m_key, (unsigned char *)&buf[0], buf.length());
    else
        ret = pk_write_pubkey_der(&m_key, (unsigned char *)&buf[0], buf.length());
    if (ret < 0)
        return CHECK_ERROR(_ssl::setError(ret));

    retVal = new Buffer(buf.substr(buf.length() - ret));

    return 0;
}
Exemple #8
0
static CURLcode
polarssl_connect_step2(struct connectdata *conn,
                       int sockindex)
{
  int ret;
  struct Curl_easy *data = conn->data;
  struct ssl_connect_data* connssl = &conn->ssl[sockindex];
  char buffer[1024];
  const char * const pinnedpubkey = SSL_IS_PROXY() ?
            data->set.str[STRING_SSL_PINNEDPUBLICKEY_PROXY] :
            data->set.str[STRING_SSL_PINNEDPUBLICKEY_ORIG];


  char errorbuf[128];
  errorbuf[0] = 0;

  conn->recv[sockindex] = polarssl_recv;
  conn->send[sockindex] = polarssl_send;

  ret = ssl_handshake(&BACKEND->ssl);

  switch(ret) {
  case 0:
    break;

  case POLARSSL_ERR_NET_WANT_READ:
    connssl->connecting_state = ssl_connect_2_reading;
    return CURLE_OK;

  case POLARSSL_ERR_NET_WANT_WRITE:
    connssl->connecting_state = ssl_connect_2_writing;
    return CURLE_OK;

  default:
    error_strerror(ret, errorbuf, sizeof(errorbuf));
    failf(data, "ssl_handshake returned - PolarSSL: (-0x%04X) %s",
          -ret, errorbuf);
    return CURLE_SSL_CONNECT_ERROR;
  }

  infof(data, "PolarSSL: Handshake complete, cipher is %s\n",
        ssl_get_ciphersuite(&BACKEND->ssl) );

  ret = ssl_get_verify_result(&BACKEND->ssl);

  if(ret && SSL_CONN_CONFIG(verifypeer)) {
    if(ret & BADCERT_EXPIRED)
      failf(data, "Cert verify failed: BADCERT_EXPIRED");

    if(ret & BADCERT_REVOKED) {
      failf(data, "Cert verify failed: BADCERT_REVOKED");
      return CURLE_SSL_CACERT;
    }

    if(ret & BADCERT_CN_MISMATCH)
      failf(data, "Cert verify failed: BADCERT_CN_MISMATCH");

    if(ret & BADCERT_NOT_TRUSTED)
      failf(data, "Cert verify failed: BADCERT_NOT_TRUSTED");

    return CURLE_PEER_FAILED_VERIFICATION;
  }

  if(ssl_get_peer_cert(&(BACKEND->ssl))) {
    /* If the session was resumed, there will be no peer certs */
    memset(buffer, 0, sizeof(buffer));

    if(x509_crt_info(buffer, sizeof(buffer), (char *)"* ",
                     ssl_get_peer_cert(&(BACKEND->ssl))) != -1)
      infof(data, "Dumping cert info:\n%s\n", buffer);
  }

  /* adapted from mbedtls.c */
  if(pinnedpubkey) {
    int size;
    CURLcode result;
    x509_crt *p;
    unsigned char pubkey[PUB_DER_MAX_BYTES];
    const x509_crt *peercert;

    peercert = ssl_get_peer_cert(&BACKEND->ssl);

    if(!peercert || !peercert->raw.p || !peercert->raw.len) {
      failf(data, "Failed due to missing peer certificate");
      return CURLE_SSL_PINNEDPUBKEYNOTMATCH;
    }

    p = calloc(1, sizeof(*p));

    if(!p)
      return CURLE_OUT_OF_MEMORY;

    x509_crt_init(p);

    /* Make a copy of our const peercert because pk_write_pubkey_der
       needs a non-const key, for now.
       https://github.com/ARMmbed/mbedtls/issues/396 */
    if(x509_crt_parse_der(p, peercert->raw.p, peercert->raw.len)) {
      failf(data, "Failed copying peer certificate");
      x509_crt_free(p);
      free(p);
      return CURLE_SSL_PINNEDPUBKEYNOTMATCH;
    }

    size = pk_write_pubkey_der(&p->pk, pubkey, PUB_DER_MAX_BYTES);

    if(size <= 0) {
      failf(data, "Failed copying public key from peer certificate");
      x509_crt_free(p);
      free(p);
      return CURLE_SSL_PINNEDPUBKEYNOTMATCH;
    }

    /* pk_write_pubkey_der writes data at the end of the buffer. */
    result = Curl_pin_peer_pubkey(data,
                                  pinnedpubkey,
                                  &pubkey[PUB_DER_MAX_BYTES - size], size);
    if(result) {
      x509_crt_free(p);
      free(p);
      return result;
    }

    x509_crt_free(p);
    free(p);
  }

#ifdef HAS_ALPN
  if(conn->bits.tls_enable_alpn) {
    const char *next_protocol = ssl_get_alpn_protocol(&BACKEND->ssl);

    if(next_protocol != NULL) {
      infof(data, "ALPN, server accepted to use %s\n", next_protocol);

#ifdef USE_NGHTTP2
      if(!strncmp(next_protocol, NGHTTP2_PROTO_VERSION_ID,
                  NGHTTP2_PROTO_VERSION_ID_LEN)) {
        conn->negnpn = CURL_HTTP_VERSION_2;
      }
      else
#endif
        if(!strncmp(next_protocol, ALPN_HTTP_1_1, ALPN_HTTP_1_1_LENGTH)) {
          conn->negnpn = CURL_HTTP_VERSION_1_1;
        }
    }
    else
      infof(data, "ALPN, server did not agree to a protocol\n");
  }
#endif

  connssl->connecting_state = ssl_connect_3;
  infof(data, "SSL connected\n");

  return CURLE_OK;
}
Exemple #9
0
int x509write_csr_der( x509write_csr *ctx, unsigned char *buf, size_t size,
                       int (*f_rng)(void *, unsigned char *, size_t),
                       void *p_rng )
{
    int ret;
    const char *sig_oid;
    size_t sig_oid_len = 0;
    unsigned char *c, *c2;
    unsigned char hash[64];
    unsigned char sig[POLARSSL_MPI_MAX_SIZE];
    unsigned char tmp_buf[2048];
    size_t pub_len = 0, sig_and_oid_len = 0, sig_len;
    size_t len = 0;
    pk_type_t pk_alg;

    /*
     * Prepare data to be signed in tmp_buf
     */
    c = tmp_buf + sizeof( tmp_buf );

    ASN1_CHK_ADD( len, x509_write_extensions( &c, tmp_buf, ctx->extensions ) );

    if( len )
    {
        ASN1_CHK_ADD( len, asn1_write_len( &c, tmp_buf, len ) );
        ASN1_CHK_ADD( len, asn1_write_tag( &c, tmp_buf, ASN1_CONSTRUCTED |
                                                        ASN1_SEQUENCE ) );

        ASN1_CHK_ADD( len, asn1_write_len( &c, tmp_buf, len ) );
        ASN1_CHK_ADD( len, asn1_write_tag( &c, tmp_buf, ASN1_CONSTRUCTED |
                                                        ASN1_SET ) );

        ASN1_CHK_ADD( len, asn1_write_oid( &c, tmp_buf, OID_PKCS9_CSR_EXT_REQ,
                                          OID_SIZE( OID_PKCS9_CSR_EXT_REQ ) ) );

        ASN1_CHK_ADD( len, asn1_write_len( &c, tmp_buf, len ) );
        ASN1_CHK_ADD( len, asn1_write_tag( &c, tmp_buf, ASN1_CONSTRUCTED |
                                                        ASN1_SEQUENCE ) );
    }

    ASN1_CHK_ADD( len, asn1_write_len( &c, tmp_buf, len ) );
    ASN1_CHK_ADD( len, asn1_write_tag( &c, tmp_buf, ASN1_CONSTRUCTED |
                                                    ASN1_CONTEXT_SPECIFIC ) );

    ASN1_CHK_ADD( pub_len, pk_write_pubkey_der( ctx->key,
                                                tmp_buf, c - tmp_buf ) );
    c -= pub_len;
    len += pub_len;

    /*
     *  Subject  ::=  Name
     */
    ASN1_CHK_ADD( len, x509_write_names( &c, tmp_buf, ctx->subject ) );

    /*
     *  Version  ::=  INTEGER  {  v1(0), v2(1), v3(2)  }
     */
    ASN1_CHK_ADD( len, asn1_write_int( &c, tmp_buf, 0 ) );

    ASN1_CHK_ADD( len, asn1_write_len( &c, tmp_buf, len ) );
    ASN1_CHK_ADD( len, asn1_write_tag( &c, tmp_buf, ASN1_CONSTRUCTED |
                                                    ASN1_SEQUENCE ) );

    /*
     * Prepare signature
     */
    md( md_info_from_type( ctx->md_alg ), c, len, hash );

    if( ( ret = pk_sign( ctx->key, ctx->md_alg, hash, 0, sig, &sig_len,
                         f_rng, p_rng ) ) != 0 )
    {
        return( ret );
    }

    if( pk_can_do( ctx->key, POLARSSL_PK_RSA ) )
        pk_alg = POLARSSL_PK_RSA;
    else if( pk_can_do( ctx->key, POLARSSL_PK_ECDSA ) )
        pk_alg = POLARSSL_PK_ECDSA;
    else
        return( POLARSSL_ERR_X509_INVALID_ALG );

    if( ( ret = oid_get_oid_by_sig_alg( pk_alg, ctx->md_alg,
                                        &sig_oid, &sig_oid_len ) ) != 0 )
    {
        return( ret );
    }

    /*
     * Write data to output buffer
     */
    c2 = buf + size;
    ASN1_CHK_ADD( sig_and_oid_len, x509_write_sig( &c2, buf,
                                        sig_oid, sig_oid_len, sig, sig_len ) );

    if( len > (size_t)( c2 - buf ) )
        return( POLARSSL_ERR_ASN1_BUF_TOO_SMALL );

    c2 -= len;
    memcpy( c2, c, len );

    len += sig_and_oid_len;
    ASN1_CHK_ADD( len, asn1_write_len( &c2, buf, len ) );
    ASN1_CHK_ADD( len, asn1_write_tag( &c2, buf, ASN1_CONSTRUCTED |
                                                 ASN1_SEQUENCE ) );

    return( (int) len );
}
static int check_trusted_key_cert(unsigned char *buf, size_t len)
{
	const unsigned char *p;
	size_t sz;
	int err, flags;

	x509_crt_init(&cert);

	/* Parse the Trusted Key certificate */
	err = x509_crt_parse(&cert, buf, len);
	if (err) {
		ERROR("Trusted Key certificate parse error %d.\n", err);
		goto error;
	}

	/* Verify Trusted Key certificate */
	err = x509_crt_verify(&cert, &cert, NULL, NULL, &flags, NULL, NULL);
	if (err) {
		ERROR("Trusted Key certificate verification error %d. Flags: "
				"0x%x.\n", err, flags);
		goto error;
	}

	/* Check that it has been signed with the ROT key */
	err = pk_write_pubkey_der(&cert.pk, pk_buf, sizeof(pk_buf));
	if (err < 0) {
		ERROR("Error loading ROT key in DER format %d.\n", err);
		goto error;
	}

	sz = (size_t)err;
	p = pk_buf + sizeof(pk_buf) - sz;

	if (plat_match_rotpk(p, sz)) {
		ERROR("ROT and Trusted Key certificate key mismatch\n");
		goto error;
	}

	/* Extract Trusted World key from extensions */
	err = x509_get_crt_ext_data(&p, &tz_world_pk_len,
			&cert, TZ_WORLD_PK_OID);
	if (err) {
		ERROR("Cannot read Trusted World key\n");
		goto error;
	}

	assert(tz_world_pk_len <= RSA_PUB_DER_MAX_BYTES);
	memcpy(tz_world_pk, p, tz_world_pk_len);

	/* Extract Non-Trusted World key from extensions */
	err = x509_get_crt_ext_data(&p, &ntz_world_pk_len,
			&cert, NTZ_WORLD_PK_OID);
	if (err) {
		ERROR("Cannot read Non-Trusted World key\n");
		goto error;
	}

	assert(tz_world_pk_len <= RSA_PUB_DER_MAX_BYTES);
	memcpy(ntz_world_pk, p, ntz_world_pk_len);

error:
	x509_crt_free(&cert);

	return err;
}
Exemple #11
0
int x509write_crt_der( x509write_cert *ctx, unsigned char *buf, size_t size,
                       int (*f_rng)(void *, unsigned char *, size_t),
                       void *p_rng )
{
    int ret;
    const char *sig_oid;
    size_t sig_oid_len = 0;
    unsigned char *c, *c2;
    unsigned char hash[64];
    unsigned char sig[POLARSSL_MPI_MAX_SIZE];
    unsigned char tmp_buf[2048];
    size_t sub_len = 0, pub_len = 0, sig_and_oid_len = 0, sig_len;
    size_t len = 0;
    pk_type_t pk_alg;

    /*
     * Prepare data to be signed in tmp_buf
     */
    c = tmp_buf + sizeof( tmp_buf );

    /* Signature algorithm needed in TBS, and later for actual signature */
    pk_alg = pk_get_type( ctx->issuer_key );
    if( pk_alg == POLARSSL_PK_ECKEY )
        pk_alg = POLARSSL_PK_ECDSA;

    if( ( ret = oid_get_oid_by_sig_alg( pk_alg, ctx->md_alg,
                                        &sig_oid, &sig_oid_len ) ) != 0 )
    {
        return( ret );
    }

    /*
     *  Extensions  ::=  SEQUENCE SIZE (1..MAX) OF Extension
     */
    ASN1_CHK_ADD( len, x509_write_extensions( &c, tmp_buf, ctx->extensions ) );
    ASN1_CHK_ADD( len, asn1_write_len( &c, tmp_buf, len ) );
    ASN1_CHK_ADD( len, asn1_write_tag( &c, tmp_buf, ASN1_CONSTRUCTED | ASN1_SEQUENCE ) );
    ASN1_CHK_ADD( len, asn1_write_len( &c, tmp_buf, len ) );
    ASN1_CHK_ADD( len, asn1_write_tag( &c, tmp_buf, ASN1_CONTEXT_SPECIFIC | ASN1_CONSTRUCTED | 3 ) );

    /*
     *  SubjectPublicKeyInfo
     */
    ASN1_CHK_ADD( pub_len, pk_write_pubkey_der( ctx->subject_key,
                                                tmp_buf, c - tmp_buf ) );
    c -= pub_len;
    len += pub_len;

    /*
     *  Subject  ::=  Name
     */
    ASN1_CHK_ADD( len, x509_write_names( &c, tmp_buf, ctx->subject ) );

    /*
     *  Validity ::= SEQUENCE {
     *       notBefore      Time,
     *       notAfter       Time }
     */
    sub_len = 0;

    ASN1_CHK_ADD( sub_len, x509_write_time( &c, tmp_buf, ctx->not_after,
                                            X509_RFC5280_UTC_TIME_LEN ) );

    ASN1_CHK_ADD( sub_len, x509_write_time( &c, tmp_buf, ctx->not_before,
                                            X509_RFC5280_UTC_TIME_LEN ) );

    len += sub_len;
    ASN1_CHK_ADD( len, asn1_write_len( &c, tmp_buf, sub_len ) );
    ASN1_CHK_ADD( len, asn1_write_tag( &c, tmp_buf, ASN1_CONSTRUCTED | ASN1_SEQUENCE ) );

    /*
     *  Issuer  ::=  Name
     */
    ASN1_CHK_ADD( len, x509_write_names( &c, tmp_buf, ctx->issuer ) );

    /*
     *  Signature   ::=  AlgorithmIdentifier
     */
    ASN1_CHK_ADD( len, asn1_write_algorithm_identifier( &c, tmp_buf,
                       sig_oid, strlen( sig_oid ), 0 ) );

    /*
     *  Serial   ::=  INTEGER
     */
    ASN1_CHK_ADD( len, asn1_write_mpi( &c, tmp_buf, &ctx->serial ) );

    /*
     *  Version  ::=  INTEGER  {  v1(0), v2(1), v3(2)  }
     */
    sub_len = 0;
    ASN1_CHK_ADD( sub_len, asn1_write_int( &c, tmp_buf, ctx->version ) );
    len += sub_len;
    ASN1_CHK_ADD( len, asn1_write_len( &c, tmp_buf, sub_len ) );
    ASN1_CHK_ADD( len, asn1_write_tag( &c, tmp_buf, ASN1_CONTEXT_SPECIFIC | ASN1_CONSTRUCTED | 0 ) );

    ASN1_CHK_ADD( len, asn1_write_len( &c, tmp_buf, len ) );
    ASN1_CHK_ADD( len, asn1_write_tag( &c, tmp_buf, ASN1_CONSTRUCTED | ASN1_SEQUENCE ) );

    /*
     * Make signature
     */
    md( md_info_from_type( ctx->md_alg ), c, len, hash );

    if( ( ret = pk_sign( ctx->issuer_key, ctx->md_alg, hash, 0, sig, &sig_len,
                         f_rng, p_rng ) ) != 0 )
    {
        return( ret );
    }

    /*
     * Write data to output buffer
     */
    c2 = buf + size;
    ASN1_CHK_ADD( sig_and_oid_len, x509_write_sig( &c2, buf,
                                        sig_oid, sig_oid_len, sig, sig_len ) );

    c2 -= len;
    memcpy( c2, c, len );

    len += sig_and_oid_len;
    ASN1_CHK_ADD( len, asn1_write_len( &c2, buf, len ) );
    ASN1_CHK_ADD( len, asn1_write_tag( &c2, buf, ASN1_CONSTRUCTED | ASN1_SEQUENCE ) );

    return( (int) len );
}