Esempio n. 1
0
File: crl.c Progetto: world100/11111
static X509_REVOKED *create_revoked(const BIGNUM* bn, time_t t, int reason)
{
  X509_REVOKED *revoked = X509_REVOKED_new();
  ASN1_TIME *tm = ASN1_TIME_new();
  ASN1_INTEGER *it =  BN_to_ASN1_INTEGER(bn, NULL);;

  ASN1_TIME_set(tm, t);

  X509_REVOKED_set_revocationDate(revoked, tm);
  X509_REVOKED_set_serialNumber(revoked, it);

  {
    ASN1_ENUMERATED * e = ASN1_ENUMERATED_new();
    X509_EXTENSION * ext = X509_EXTENSION_new();

    ASN1_ENUMERATED_set(e, reason);

    X509_EXTENSION_set_data(ext, e);
    X509_EXTENSION_set_object(ext, OBJ_nid2obj(NID_crl_reason));
    X509_REVOKED_add_ext(revoked, ext, 0);

    X509_EXTENSION_free(ext);
    ASN1_ENUMERATED_free(e);
  }

  ASN1_TIME_free(tm);
  ASN1_INTEGER_free(it);

  return revoked;
}
Esempio n. 2
0
static X509_REVOKED *create_revoked(lua_State*L, const BIGNUM* bn, time_t t, int reason)
{
  X509_REVOKED *revoked = X509_REVOKED_new();
  ASN1_TIME *tm = ASN1_TIME_new();
  ASN1_INTEGER *it =  BN_to_ASN1_INTEGER((BIGNUM*)bn, NULL);;

  ASN1_TIME_set(tm, t);

  X509_REVOKED_set_revocationDate(revoked, tm);
  X509_REVOKED_set_serialNumber(revoked, it);
#if OPENSSL_VERSION_NUMBER > 0x10000000L
  revoked->reason = reason;
#else
  {
    ASN1_ENUMERATED * e = ASN1_ENUMERATED_new();
    X509_EXTENSION * ext = X509_EXTENSION_new();

    ASN1_ENUMERATED_set(e, reason);

    X509_EXTENSION_set_data(ext, e);
    X509_EXTENSION_set_object(ext, OBJ_nid2obj(NID_crl_reason));
    X509_REVOKED_add_ext(revoked, ext, 0);

    X509_EXTENSION_free(ext);
    ASN1_ENUMERATED_free(e);
  }
#endif
  ASN1_TIME_free(tm);
  ASN1_INTEGER_free(it);

  return revoked;
}
Esempio n. 3
0
void openssl_x509_crl()
{
	RSA *r;
	BIO *bp;
	int len;
	FILE *fp;
	BIGNUM *bne;
	X509_CRL *crl;
	EVP_PKEY *pkey;
	X509_NAME *issuer;
	ASN1_INTEGER *serial;
	X509_REVOKED *revoked;
	ASN1_TIME *lastUpdate, *nextUpdate, *rvTime;
	unsigned char *buf, *p, tmp[MAX1_LEN] = "crl cert";

	printf("\nX509_CRL info:\n");
	bne = BN_new();
	BN_set_word(bne, RSA_3);
	r = RSA_new();
	RSA_generate_key_ex(r, MAX1_LEN, bne, NULL);
	pkey = EVP_PKEY_new();
	EVP_PKEY_assign_RSA(pkey, r);

	crl = X509_CRL_new();
	X509_CRL_set_version(crl, 3);

	issuer = X509_NAME_new();
	X509_NAME_add_entry_by_NID(issuer, NID_commonName,
								V_ASN1_PRINTABLESTRING, tmp, 10, -1, 0);
	X509_CRL_set_issuer_name(crl, issuer);

	lastUpdate = ASN1_TIME_new();
	ASN1_TIME_set(lastUpdate, time(NULL));
	X509_CRL_set_lastUpdate(crl, lastUpdate);

	nextUpdate = ASN1_TIME_new();
	ASN1_TIME_set(nextUpdate, time(NULL) + 1280);
	X509_CRL_set_nextUpdate(crl, nextUpdate);

	revoked = X509_REVOKED_new();
	serial = ASN1_INTEGER_new();
	ASN1_INTEGER_set(serial, 1280);
	X509_REVOKED_set_serialNumber(revoked, serial);

	rvTime = ASN1_TIME_new();
	ASN1_TIME_set(rvTime, time(NULL) + 2000);
	X509_CRL_set_nextUpdate(crl, rvTime);
	X509_REVOKED_set_revocationDate(revoked, rvTime);

	X509_CRL_add0_revoked(crl, revoked);
	X509_CRL_sort(crl);
	X509_CRL_sign(crl, pkey, EVP_md5());

	bp = BIO_new(BIO_s_file());
	BIO_set_fp(bp, stdout, BIO_NOCLOSE);
	X509_CRL_print(bp, crl);
	len = i2d_X509_CRL(crl, NULL);
	buf = (unsigned char *)malloc(len + 10);
	p = buf;
	len = i2d_X509_CRL(crl, &p);
	fp = fopen("/tmp/crl.crl", "wb");
	fwrite(buf, 1, len, fp);
	fclose(fp);

	free(buf);
	BIO_free(bp);
	X509_CRL_free(crl);
}
Esempio n. 4
0
DWORD
VMCACreateRevokedFromCert(
    X509 *pCert,
    X509_REVOKED **pRevoked)
{

    DWORD dwError = 0;
    X509_REVOKED *pTempRev = NULL;
    ASN1_TIME *pRevTime = NULL;
    ASN1_ENUMERATED *pCode = NULL;

    pCode = ASN1_ENUMERATED_new();
    if(pCode == NULL) {
        dwError = VMCA_OUT_MEMORY_ERR;
        BAIL_ON_ERROR(dwError);
    }

    pTempRev = X509_REVOKED_new();
    if (pTempRev == NULL) {
        dwError = VMCA_OUT_MEMORY_ERR;
        BAIL_ON_ERROR(dwError);
    }

    pRevTime = ASN1_TIME_new();
    if (pRevTime == NULL) {
        dwError = VMCA_OUT_MEMORY_ERR;
        BAIL_ON_ERROR(dwError);
    }

    ASN1_TIME_set(pRevTime, time(NULL));
    dwError = X509_REVOKED_set_serialNumber(pTempRev,
                    X509_get_serialNumber(pCert));
    BAIL_ON_SSL_ERROR(dwError, VMCA_CRL_SET_SERIAL_FAIL);

    dwError = X509_REVOKED_set_revocationDate(pTempRev, pRevTime);
    BAIL_ON_SSL_ERROR(dwError, VMCA_CRL_SET_TIME_FAIL);

    //TODO : Fix the UNSPECIFIED to real valid reason
    // which users can pass in.
    ASN1_ENUMERATED_set(pCode, CRL_REASON_UNSPECIFIED);
    dwError = X509_REVOKED_add1_ext_i2d(pTempRev,
                            NID_crl_reason, pCode, 0, 0);

    BAIL_ON_SSL_ERROR(dwError, VMCA_CRL_REASON_FAIL);
    *pRevoked = pTempRev;

cleanup :
    if(pRevTime != NULL) {
        ASN1_TIME_free(pRevTime);
    }

    if(pCode !=NULL) {
        ASN1_ENUMERATED_free(pCode);
    }
    return dwError;

error:
    if(pTempRev != NULL)
    {
        X509_REVOKED_free(pTempRev);
    }
    goto cleanup;
}
Esempio n. 5
0
DWORD
VMCACreateRevokedFromCert_Reason(
    ASN1_INTEGER *asnSerial,
    DWORD dwRevokedDate,
    VMCA_CRL_REASON certRevokeReason,
    X509_REVOKED **pRevoked)
{

    DWORD dwError = 0;
    X509_REVOKED *pTempRev = NULL;
    ASN1_TIME *pRevTime = NULL;
    ASN1_ENUMERATED *pCode = NULL;

    pCode = ASN1_ENUMERATED_new();
    if(pCode == NULL) {
        dwError = VMCA_OUT_MEMORY_ERR;
        BAIL_ON_ERROR(dwError);
    }

    pTempRev = X509_REVOKED_new();
    if (pTempRev == NULL) {
        dwError = VMCA_OUT_MEMORY_ERR;
        BAIL_ON_ERROR(dwError);
    }

    pRevTime = ASN1_TIME_new();
    if (pRevTime == NULL) {
        dwError = VMCA_OUT_MEMORY_ERR;
        BAIL_ON_ERROR(dwError);
    }

    ASN1_TIME_set(pRevTime, (time_t)dwRevokedDate);
    dwError = X509_REVOKED_set_serialNumber(pTempRev,
                                            asnSerial);
    BAIL_ON_SSL_ERROR(dwError, VMCA_CRL_SET_SERIAL_FAIL);

    dwError = X509_REVOKED_set_revocationDate(pTempRev, pRevTime);
    BAIL_ON_SSL_ERROR(dwError, VMCA_CRL_SET_TIME_FAIL);

    ASN1_ENUMERATED_set(pCode, certRevokeReason);
    dwError = X509_REVOKED_add1_ext_i2d(pTempRev,
                            NID_crl_reason, pCode, 0, 0);

    BAIL_ON_SSL_ERROR(dwError, VMCA_CRL_REASON_FAIL);
    *pRevoked = pTempRev;

cleanup :
    if(pRevTime != NULL) {
        ASN1_TIME_free(pRevTime);
    }

    if(pCode !=NULL) {
        ASN1_ENUMERATED_free(pCode);
    }
    return dwError;

error:
    if(pTempRev != NULL)
    {
        X509_REVOKED_free(pTempRev);
    }
    goto cleanup;
}
Esempio n. 6
0
X509_REVOKED *openssl_X509_REVOKED(lua_State*L, int snidx, int timeidx, int reasonidx) {
    X509_REVOKED *revoked = X509_REVOKED_new();
    const char* serial = luaL_checkstring(L, snidx);
    BIGNUM * bn = NULL;
    ASN1_TIME *tm = NULL;
    int reason = 0;
    ASN1_INTEGER *it = NULL;


    if(!BN_hex2bn(&bn, serial))
    {
        goto end;
    };

    if(lua_isnumber(L,timeidx) || lua_isnoneornil(L, timeidx))
    {
        time_t t;
        time(&t);
        t = luaL_optinteger(L, 3, (lua_Integer)t);
        tm = ASN1_TIME_new();
        ASN1_TIME_set(tm,t);
    } else if(lua_isstring(L, timeidx))
    {

    } else {
        goto end;
    }

    if(lua_isnumber(L, reasonidx) || lua_isnoneornil(L, reasonidx))
    {
        reason = luaL_optinteger(L, reasonidx, 0);
        if(reason < 0 || reason >= reason_num) {
            goto end;
        }

    } else if(lua_isstring(L, reasonidx))
    {
        const char* s = lua_tostring(L, reasonidx);
        reason = openssl_get_revoke_reason(s);
        if(reason < 0 || reason >= reason_num) {
            goto end;
        }
    } else
    {
        goto end;
    };

    it = BN_to_ASN1_INTEGER(bn,NULL);
    X509_REVOKED_set_revocationDate(revoked, tm);
    X509_REVOKED_set_serialNumber(revoked, it);
#if OPENSSL_VERSION_NUMBER > 0x10000000L
    revoked->reason = reason;
#else
    /*
    {
        ASN1_ENUMERATED * e = ASN1_ENUMERATED_new();
    	X509_EXTENSION * ext = X509_EXTENSION_new();

        ASN1_ENUMERATED_set(e, reason);

        X509_EXTENSION_set_object(ext, OBJ_nid2obj(NID_crl_reason));
        X509_EXTENSION_set_data(ext,e);

        if(!revoked->extensions)
            revoked->extensions = sk_X509_EXTENSION_new_null();

    	X509_REVOKED_add_ext()
        sk_X509_REVOKED_push(revoked->extensions,ext);

        X509_EXTENSION_free(ext);
        ASN1_ENUMERATED_free(e);
    }
    */
#endif

    ASN1_TIME_free(tm);
    ASN1_INTEGER_free(it);
    BN_free(bn);

    return revoked;
end:
    X509_REVOKED_free(revoked);
    ASN1_TIME_free(tm);
    ASN1_INTEGER_free(it);
    BN_free(bn);
    return NULL;
}
Esempio n. 7
0
PKI_X509_CRL_ENTRY * PKI_X509_CRL_ENTRY_new_serial( const char *serial, 
          PKI_X509_CRL_REASON reason, const PKI_TIME *revDate,
          const PKI_X509_PROFILE *profile ) {

  PKI_X509_CRL_ENTRY *entry = NULL;
    // Entry to be added to the CRL

  PKI_INTEGER * s_int = NULL;
    // ASN1 Integer

  PKI_TIME * a_date = NULL;
    // ASN1 Rev Date

  // Input check
  if (!serial) {
    PKI_ERROR(PKI_ERR_PARAM_NULL, "Missing serial number");
    return NULL;
  }

  // Allocates the Memory for the entry
  if((entry = (PKI_X509_CRL_ENTRY *) X509_REVOKED_new()) == NULL ) {
    PKI_ERROR(PKI_ERR_MEMORY_ALLOC, NULL);
    return NULL;
  }

  // If no revocation date is provided, let's use "now"
  if (!revDate && (a_date = PKI_TIME_new(0)) == NULL) {

    // Can not allocate the revocation date time
    PKI_ERROR(PKI_ERR_MEMORY_ALLOC, NULL);
    return NULL;

  } else {

    // Gets the Pointer from the caller
    a_date = (PKI_TIME *)revDate;
  }

  // Generates the integer carrying the serial number
  if ((s_int = PKI_INTEGER_new_char(serial)) != NULL) {

    // Sets the serial number in the X509_REVOKED structure
    if (X509_REVOKED_set_serialNumber(entry, s_int) == 1) {

      // Sets the revocation date
      if (a_date && !X509_REVOKED_set_revocationDate((X509_REVOKED *) entry, a_date)) {
        PKI_ERROR(PKI_ERR_GENERAL, "Can not assign revocation date");
        goto err;
      }

      // All Ok here

    } else {

      // Error While assigning the serial
      PKI_ERROR(PKI_ERR_MEMORY_ALLOC, "Can not assign the serial (%s)", serial);
      goto err;
    }

  } else {

    // Error generating the ASN1 Integer
    PKI_ERROR(PKI_ERR_MEMORY_ALLOC, "Can not convert serial %s to Integer", serial);
    goto err;
  }

  if (reason != PKI_CRL_REASON_UNSPECIFIED) {

    int supported_reason = -1;
    ASN1_ENUMERATED *rtmp = ASN1_ENUMERATED_new();

    switch (reason )
    {
      case PKI_CRL_REASON_CERTIFICATE_HOLD:
      case PKI_CRL_REASON_HOLD_INSTRUCTION_REJECT:
        if (!X509_REVOKED_add1_ext_i2d(entry,
                                       NID_hold_instruction_code,
                                       PKI_OID_get("holdInstructionReject"), 0, 0)) {
	  PKI_ERROR(PKI_ERR_X509_CRL, "Can not add holdInstructionReject");
          goto err;
        }

        if (revDate && !X509_REVOKED_add1_ext_i2d(entry,
            NID_invalidity_date, (PKI_TIME *)revDate, 0, 0)) {
	    PKI_ERROR(PKI_ERR_X509_CRL, "Can not add invalidity date");
          goto err;
        }

        supported_reason = PKI_CRL_REASON_CERTIFICATE_HOLD;
        break;

      /* --- Deprecated in RFC 5280 ---
      case PKI_CRL_REASON_HOLD_INSTRUCTION_NONE:
        if (!X509_REVOKED_add1_ext_i2d(entry, NID_hold_instruction_code, 
            PKI_OID_get( "holdInstructionReject"), 0, 0)) {
          goto err;
        };
        if( revDate && !X509_REVOKED_add1_ext_i2d ( entry, 
            NID_invalidity_date, revDate, 0, 0)) {
          goto err;
        };
        reason = PKI_CRL_REASON_CERTIFICATE_HOLD;
        break;
      */

      case PKI_CRL_REASON_HOLD_INSTRUCTION_CALLISSUER:
        if (!X509_REVOKED_add1_ext_i2d(
          entry, 
          NID_hold_instruction_code, 
          PKI_OID_get( 
            "holdInstructionCallIssuer"), 0, 0)) {
          goto err;
        }

        if( revDate && !X509_REVOKED_add1_ext_i2d(
              entry, 
              NID_invalidity_date, 
              (PKI_TIME *)revDate, 
              0, 0)) {
          goto err;
        }

        supported_reason = PKI_CRL_REASON_CERTIFICATE_HOLD;
        break;

      case PKI_CRL_REASON_KEY_COMPROMISE:
      case PKI_CRL_REASON_CA_COMPROMISE:
      case PKI_CRL_REASON_AFFILIATION_CHANGED:
      case PKI_CRL_REASON_SUPERSEDED:
      case PKI_CRL_REASON_CESSATION_OF_OPERATION:
      case PKI_CRL_REASON_REMOVE_FROM_CRL:
      case PKI_CRL_REASON_PRIVILEGE_WITHDRAWN:
      case PKI_CRL_REASON_AA_COMPROMISE:
        PKI_ERROR(PKI_ERR_GENERAL, "CRL Reason Not Implemented Yet %d", reason);
	break;

      default:
        PKI_ERROR(PKI_ERR_GENERAL, "CRL Reason Unknown %d", reason);
        supported_reason = -1;
        break;
    }

    if (supported_reason >= 0)
    {
      if (!ASN1_ENUMERATED_set(rtmp, supported_reason)) goto err;
      if (!X509_REVOKED_add1_ext_i2d( entry, NID_crl_reason, rtmp, 0, 0)) goto err;
    }

    /*
    if( reason == CRL_REASON_HOLD_INSTRUCTION ) {
      // if (!X509_REVOKED_add1_ext_i2d ( entry, 
      //     NID_invalidity_date, revDate, 0, 0)) {
      //   goto err;
      // };
      // if (!X509_REVOKED_add1_ext_i2d(entry, NID_hold_instruction_code, 
        //   PKI_OID_get( "holdInstructionReject"), 0, 0)) {
      // goto err;
      // };
    };
    */

  }

/*
  if (rev && !X509_REVOKED_set_revocationDate(rev, revDate))
                goto err;

        if (rev && (reason_code != OCSP_REVOKED_STATUS_NOSTATUS))
                {
                rtmp = ASN1_ENUMERATED_new();
                if (!rtmp || !ASN1_ENUMERATED_set(rtmp, reason_code))
                        goto err;
                if (!X509_REVOKED_add1_ext_i2d(rev, NID_crl_reason, rtmp, 0, 0))
                        goto err;
                }

        if (rev && comp_time)
                {
                if (!X509_REVOKED_add1_ext_i2d(rev, NID_invalidity_date, comp_time, 0, 0))
                        goto err;
                }
  if (rev && hold)
                {
                if (!X509_REVOKED_add1_ext_i2d(rev, NID_hold_instruction_code, hold, 0, 0))
                        goto err;
                }

*/

  // Free Allocated Memory
  if (s_int) PKI_INTEGER_free(s_int);
  if (a_date && !revDate) PKI_TIME_free(a_date);

  // Returns the created entry
  return entry;

err:

  // Free Allocated memory
  if (s_int) PKI_INTEGER_free(s_int);
  if (a_date && !revDate) PKI_TIME_free(a_date);
  if (entry) X509_REVOKED_free((X509_REVOKED *) entry);

  // Returns null (error)
  return NULL;
}
int addToCRL(char* pemSigningKey, char* pemOldCrl, char* pemRevokedCert, char* result) {
  int err = 0;

  BIO* bioSigningKey = BIO_new_mem_buf(pemSigningKey, -1);
  if (!bioSigningKey) {
    return ERR_peek_error();
  }
  BIO* bioRevCert = BIO_new_mem_buf(pemRevokedCert, -1);
  if (!bioRevCert) {
    BIO_free(bioSigningKey);
    return ERR_peek_error();
  }
  BIO* bioOldCRL = BIO_new_mem_buf(pemOldCrl, -1);
  if (!bioOldCRL) {
    BIO_free(bioSigningKey);
    BIO_free(bioRevCert);
    return ERR_peek_error();
  }

  X509* badCert = PEM_read_bio_X509(bioRevCert, NULL, NULL, NULL);
  if (!badCert) {
    BIO_free(bioSigningKey);
    BIO_free(bioRevCert);
    return ERR_peek_error();
  }

  EVP_PKEY* caKey = PEM_read_bio_PrivateKey(bioSigningKey, NULL, NULL, NULL);
  if (!caKey) {
    BIO_free(bioSigningKey);
    BIO_free(bioRevCert);
    return -18;
  }

  X509_CRL* crl = PEM_read_bio_X509_CRL(bioOldCRL, NULL, NULL, NULL);
  if (!crl) {
    BIO_free(bioSigningKey);
    BIO_free(bioRevCert);
    return ERR_peek_error();
  }

  X509_REVOKED* revoked = X509_REVOKED_new();
  X509_REVOKED_set_serialNumber(revoked, X509_get_serialNumber(badCert));
  ASN1_TIME* tmptm = ASN1_TIME_new();
  X509_gmtime_adj(tmptm, long(0));
  X509_REVOKED_set_revocationDate(revoked, tmptm);

  //set the reason?  Not yet.
  //    ASN1_ENUMERATED* rtmp = ASN1_ENUMERATED_new();
  //  ASN1_ENUMERATED_set(rtmp, reasonCode);
  //    goto err;
  //  if (!X509_REVOKED_add1_ext_i2d(rev, NID_crl_reason, rtmp, 0, 0))
  //    goto err;
  //  }

  if(!(err = X509_CRL_add0_revoked(crl,revoked))) {
    BIO_free(bioSigningKey);
    BIO_free(bioRevCert);
    return err;
  }

  X509_CRL_sort(crl);

  if(!(err=X509_CRL_sign(crl,caKey,EVP_sha1()))) {
    BIO_free(bioSigningKey);
    BIO_free(bioRevCert);
    return err;
  }

  BIO *mem = BIO_new(BIO_s_mem());
  PEM_write_bio_X509_CRL(mem,crl);
  BUF_MEM *bptr;
  BIO_get_mem_ptr(mem, &bptr);
  BIO_read(mem, result, bptr->length);


  BIO_free(bioRevCert);
  BIO_free(bioSigningKey);
  BIO_free(bioOldCRL);
  BIO_free(mem);

  return 0;
}
Esempio n. 9
0
File: 2cca.c Progetto: randunel/2cca
/*
 * Revoke one certificate at a time
 * No check performed to see if certificate already revoked.
 */
void revoke_cert(char * ca_name, char * name)
{
    char filename[FIELD_SZ+5];
    FILE * f ;
    X509_CRL * crl ;
    X509 * cert ;
    ASN1_INTEGER * r_serial ;
    ASN1_INTEGER * crlnum ;
    X509_REVOKED * rev ;
    ASN1_TIME * tm ;
    identity ca ;
    BIO * out ;
    BIGNUM * b_crlnum ;

    /* Find requested certificate by name */
    sprintf(filename, "%s.crt", name);
    if ((f=fopen(filename, "r"))==NULL) {
        fprintf(stderr, "Cannot find: %s\n", filename);
        return ; 
    }
    cert = PEM_read_X509(f, NULL, NULL, NULL);
    fclose(f);
    /* Get certificate serial number */
    r_serial = X509_get_serialNumber(cert);

    /* Find out if if was already revoked */

    /* Make a revoked object with that serial */
    rev = X509_REVOKED_new();
    X509_REVOKED_set_serialNumber(rev, r_serial);
    X509_free(cert);
    /* Set reason to unspecified */
    rev->reason = ASN1_ENUMERATED_get(CRL_REASON_UNSPECIFIED);

    /* Load or create new CRL */
    if ((crl = load_crl(ca_name))==NULL) {
        crl = X509_CRL_new();
        X509_CRL_set_version(crl, 1);
        /* Set CRL number */
        crlnum = ASN1_INTEGER_new();
        ASN1_INTEGER_set(crlnum, 1);
        X509_CRL_add1_ext_i2d(crl, NID_crl_number, crlnum, 0, 0);
        ASN1_INTEGER_free(crlnum);
    } else {
        crlnum = X509_CRL_get_ext_d2i(crl, NID_crl_number, 0, 0);
        b_crlnum = ASN1_INTEGER_to_BN(crlnum, NULL);
        BN_add_word(b_crlnum, 1);
        BN_to_ASN1_INTEGER(b_crlnum, crlnum);
        BN_free(b_crlnum);
        X509_CRL_add1_ext_i2d(crl, NID_crl_number, crlnum, 0, X509V3_ADD_REPLACE_EXISTING);
        ASN1_INTEGER_free(crlnum);
    }

    /* What time is it? */
    tm = ASN1_TIME_new();
    X509_gmtime_adj(tm, 0);
    X509_REVOKED_set_revocationDate(rev, tm);
    X509_CRL_set_lastUpdate(crl, tm);

    /* Set CRL next update to a year from now */
    X509_gmtime_adj(tm, 365*24*60*60);
    X509_CRL_set_nextUpdate(crl, tm);
    ASN1_TIME_free(tm);

    /* Add revoked to CRL */
    X509_CRL_add0_revoked(crl, rev);    
    X509_CRL_sort(crl);

    /* Load root key to sign CRL */
    if (load_ca(ca_name, &ca)!=0) {
        fprintf(stderr, "Cannot find CA key/crt\n");
        return ;
    }
    X509_CRL_set_issuer_name(crl, X509_get_subject_name(ca.cert));
    X509_free(ca.cert);

    /* Sign CRL */
    X509_CRL_sign(crl, ca.key, EVP_sha256());
    EVP_PKEY_free(ca.key);

    /* Dump CRL */
    sprintf(filename, "%s.crl", ca_name);
    if ((f = fopen(filename, "wb"))==NULL) {
        fprintf(stderr, "Cannot write %s: aborting\n", filename);
        X509_CRL_free(crl);
        return ;
    }
    out = BIO_new(BIO_s_file());
    BIO_set_fp(out, f, BIO_NOCLOSE);
    PEM_write_bio_X509_CRL(out, crl);
    BIO_free_all(out);
    fclose(f);
    X509_CRL_free(crl);
    return ;
}