All Downloads are FREE. Search and download functionalities are using the official Maven repository.

org.xipki.ca.gateway.acme.CertEnroller Maven / Gradle / Ivy

There is a newer version: 6.5.1
Show newest version
// Copyright (c) 2013-2023 xipki. All rights reserved.
// License Apache License 2.0

package org.xipki.ca.gateway.acme;

import org.bouncycastle.asn1.pkcs.CertificationRequest;
import org.bouncycastle.asn1.x509.Certificate;
import org.bouncycastle.asn1.x509.Extensions;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
import org.xipki.ca.gateway.GatewayUtil;
import org.xipki.ca.gateway.acme.type.CertReqMeta;
import org.xipki.ca.gateway.acme.type.OrderStatus;
import org.xipki.ca.sdk.*;
import org.xipki.pki.OperationException;
import org.xipki.security.util.X509Util;
import org.xipki.util.Args;
import org.xipki.util.LogUtil;

import java.io.IOException;
import java.util.Iterator;

/**
 *
 * @author Lijun Liao (xipki)
 */
public class CertEnroller implements Runnable {

  private static final Logger LOG = LoggerFactory.getLogger(CertEnroller.class);

  private final AcmeRepo repo;

  private final SdkClient sdk;

  public CertEnroller(AcmeRepo repo, SdkClient sdk) {
    this.repo = Args.notNull(repo, "repo");
    this.sdk = Args.notNull(sdk, "sdk");
  }

  private boolean stopMe;

  @Override
  public void run() {
    while (!stopMe) {
      try {
        singleRun();
      } catch (Throwable t) {
        LogUtil.error(LOG, t, "expected error");
      }

      try {
        Thread.sleep(1000); // sleep for 1 second.
      } catch (InterruptedException e) {
      }
    }
  }

  public void singleRun() throws AcmeSystemException {
    Iterator orderIds = repo.getOrdersToEnroll();

    while (orderIds.hasNext()) {
      Long orderId = orderIds.next();
      if (orderId == null) {
        continue;
      }

      String orderIdStr = AcmeUtils.toBase64(orderId) + " (" + orderId + ")";
      LOG.info("try to enroll certificate for order {}", orderIdStr);

      AcmeOrder order = repo.getOrder(orderId);
      if (order == null) {
        LOG.error("found no order for id {}", orderIdStr);
        continue;
      }

      byte[] csr = order.getCsr();
      if (csr == null) {
        // if the order is read from database, csr is null in the object, even present in the database
        csr = repo.getCsr(orderId);
      }

      if (csr == null) {
        LOG.error("found not CSR for order {}", orderIdStr);
        continue;
      }

      EnrollCertRequestEntry entry = new EnrollCertRequestEntry();
      CertReqMeta certReqMeta = order.getCertReqMeta();
      entry.setNotBefore(certReqMeta.getNotBefore());
      entry.setNotAfter(certReqMeta.getNotAfter());
      entry.setCertprofile(certReqMeta.getCertProfile());

      if (certReqMeta.getSubject() == null) {
        entry.setP10req(csr);
      } else {
        entry.setSubject(new X500NameType(certReqMeta.getSubject()));

        CertificationRequest p10Req;
        try {
          p10Req = GatewayUtil.parseCsrInRequest(csr);
          Extensions extensions = X509Util.getExtensions(p10Req.getCertificationRequestInfo());
          if (extensions != null) {
            entry.setExtensions(extensions.getEncoded());
          }
          entry.setSubjectPublicKey(p10Req.getCertificationRequestInfo().getSubjectPublicKeyInfo().getEncoded());
        } catch (IOException | OperationException e) {
          throw new AcmeSystemException(e);
        }
      }

      EnrollCertsRequest sdkReq = new EnrollCertsRequest();
      sdkReq.setCaCertMode(CertsMode.NONE);
      sdkReq.setEntries(new EnrollCertRequestEntry[]{entry});

      LOG.info("start enrolling certificate for order {}", orderIdStr);
      try {
        EnrollOrPollCertsResponse sdkResp = sdk.enrollCerts(certReqMeta.getCa(), sdkReq);
        EnrollOrPullCertResponseEntry sdkRespEntry = sdkResp.getEntries()[0];
        byte[] certBytes = sdkRespEntry.getCert();
        boolean valid = certBytes != null;
        if (valid) {
          // check the certificate
          try {
            Certificate.getInstance(certBytes);
          } catch (Exception ex) {
            LogUtil.error(LOG, ex, "Error parsing enrolled certificate for order " + orderIdStr);
            valid = false;
          }
        } else {
          LOG.error("CA returned error for the order {}: {}", orderIdStr, sdkRespEntry.getError());
        }

        if (valid) {
          LOG.info("enrolled certificate for order {}", orderIdStr);
          order.setCert(certBytes);
          order.setStatus(OrderStatus.valid);
        } else {
          order.setStatus(OrderStatus.invalid);
        }

        repo.flushOrderIfNotCached(order);
      } catch (Throwable t) {
        LogUtil.error(LOG, t);
        order.setStatus(OrderStatus.invalid);
      }
    }
  }

  public void close() {
    stopMe = true;
  }

}




© 2015 - 2024 Weber Informatics LLC | Privacy Policy