/** * Updates the signing certificate of a trust bundle. * * @param bundleName The name of the trust bundle to update. * @param certData A DER encoded representation of the new signing certificate. * @return Status of 204 if the trust bundle's signing certificate was updated, status of 400 if * the signing certificate is invalid, or a status 404 if a trust bundle with the given name * does not exist. */ @POST @Path("{bundle}/signingCert") @Consumes(MediaType.APPLICATION_JSON) public Response updateSigningCert(@PathParam("bundle") String bundleName, byte[] certData) { X509Certificate signingCert = null; if (certData.length > 0) { try { signingCert = CertUtils.toX509Certificate(certData); } catch (CertificateConversionException ex) { log.error("Signing certificate is not in a valid format " + bundleName, ex); return Response.status(Status.BAD_REQUEST).cacheControl(noCache).build(); } } // make sure the bundle exists org.nhindirect.config.store.TrustBundle entityBundle; try { entityBundle = bundleDao.getTrustBundleByName(bundleName); if (entityBundle == null) return Response.status(Status.NOT_FOUND).cacheControl(noCache).build(); } catch (Exception e) { log.error("Error looking up bundle.", e); return Response.serverError().cacheControl(noCache).build(); } // now update try { bundleDao.updateTrustBundleSigningCertificate(entityBundle.getId(), signingCert); return Response.noContent().cacheControl(noCache).build(); } catch (Exception e) { log.error("Error updating trust bundle signing certificate.", e); return Response.serverError().cacheControl(noCache).build(); } }
/** * Updates multiple bundle attributes. If the URL of the bundle changes, then the bundle is * automatically refreshed. * * @param bundleName The name of the bundle to update. * @param bundleData The data of the trust bundle to update. Empty or null attributes indicate * that the attribute should not be changed. * @return Status of 204 if the bundle attributes were updated, status of 400 if the signing * certificate is invalid, or a status 404 if a trust bundle with the given name does not * exist. */ @POST @Path("{bundle}/bundleAttributes") @Consumes(MediaType.APPLICATION_JSON) public Response updateBundleAttributes( @PathParam("bundle") String bundleName, TrustBundle bundleData) { // make sure the bundle exists org.nhindirect.config.store.TrustBundle entityBundle; try { entityBundle = bundleDao.getTrustBundleByName(bundleName); if (entityBundle == null) return Response.status(Status.NOT_FOUND).cacheControl(noCache).build(); } catch (Exception e) { log.error("Error looking up bundle.", e); return Response.serverError().cacheControl(noCache).build(); } final String oldBundleURL = entityBundle.getBundleURL(); // if there is a signing certificate in the request, make sure it's valid X509Certificate newSigningCert = null; if (bundleData.getSigningCertificateData() != null) { try { newSigningCert = CertUtils.toX509Certificate(bundleData.getSigningCertificateData()); } catch (CertificateConversionException ex) { log.error("Signing certificate is not in a valid format " + bundleName, ex); return Response.status(Status.BAD_REQUEST).cacheControl(noCache).build(); } } // update the bundle try { bundleDao.updateTrustBundleAttributes( entityBundle.getId(), bundleData.getBundleName(), bundleData.getBundleURL(), newSigningCert, bundleData.getRefreshInterval()); // if the URL changed, the bundle needs to be refreshed if (bundleData.getBundleURL() != null && !bundleData.getBundleURL().isEmpty() && !oldBundleURL.equals(bundleData.getBundleURL())) { entityBundle = bundleDao.getTrustBundleById(entityBundle.getId()); template.sendBody(entityBundle); } return Response.noContent().cacheControl(noCache).build(); } catch (Exception e) { log.error("Error updating trust bundle attributes.", e); return Response.serverError().cacheControl(noCache).build(); } }
private X509Certificate certFromData(byte[] data) { X509Certificate retVal = null; try { // first check for wrapped data final CertContainer container = CertUtils.toCertContainer(data); if (container.getWrappedKeyData() != null) { // this is a wrapped key // make sure we have a KeyStoreManager configured if (this.mgr == null) { throw new NHINDException( AgentError.Unexpected, "Resolved certifiate has wrapped data, but resolver has not been configured to unwrap it."); } // create a new wrapped certificate object retVal = WrappedOnDemandX509CertificateEx.fromX509Certificate( mgr, container.getCert(), container.getWrappedKeyData()); return retVal; } ByteArrayInputStream bais = new ByteArrayInputStream(data); // lets try this a as a PKCS12 data stream first try { KeyStore localKeyStore = KeyStore.getInstance("PKCS12", CryptoExtensions.getJCEProviderName()); localKeyStore.load(bais, "".toCharArray()); Enumeration<String> aliases = localKeyStore.aliases(); // we are really expecting only one alias if (aliases.hasMoreElements()) { String alias = aliases.nextElement(); X509Certificate cert = (X509Certificate) localKeyStore.getCertificate(alias); // check if there is private key Key key = localKeyStore.getKey(alias, "".toCharArray()); if (key != null && key instanceof PrivateKey) { retVal = X509CertificateEx.fromX509Certificate(cert, (PrivateKey) key); } else retVal = cert; } } catch (Exception e) { // must not be a PKCS12 stream, go on to next step } if (retVal == null) { // try X509 certificate factory next bais.reset(); bais = new ByteArrayInputStream(data); retVal = (X509Certificate) CertificateFactory.getInstance("X.509").generateCertificate(bais); } bais.close(); } catch (Exception e) { throw new NHINDException("Data cannot be converted to a valid X.509 Certificate", e); } return retVal; }
/** * Processes all DNS CERT requests. * * @param name The record name. In many cases this a email address. * @return Returns a set of record responses to the request. * @throws DNSException */ @SuppressWarnings("unused") protected RRset processCERTRecordRequest(String name) throws DNSException { if (name.endsWith(".")) name = name.substring(0, name.length() - 1); Certificate[] certs; // use the certificate configuration service try { certs = proxy.getCertificatesForOwner(name, null); } catch (Exception e) { throw new DNSException( DNSError.newError(Rcode.SERVFAIL), "DNS service proxy call for certificates failed: " + e.getMessage(), e); } if (certs == null || certs.length == 0) { // unless the call above was for an org level cert, it will probably always fail because the // "name" parameter has had all instances of "@" replaced with ".". The certificate service // stores owners using "@". // This is horrible, but try hitting the cert service replacing each "." with "@" one by one. // Start at the beginning of the address because this is more than likely where the "@" // character // will be. int previousIndex = 0; int replaceIndex = 0; while ((replaceIndex = name.indexOf(".", previousIndex)) > -1) { char[] chars = name.toCharArray(); chars[replaceIndex] = '@'; try { certs = proxy.getCertificatesForOwner(String.copyValueOf(chars), null); } catch (Exception e) { throw new DNSException( DNSError.newError(Rcode.SERVFAIL), "DNS service proxy call for certificates failed: " + e.getMessage(), e); } if (certs != null && certs.length > 0) break; if (replaceIndex >= (name.length() - 1)) break; previousIndex = replaceIndex + 1; } } if (certs == null || certs.length == 0) return null; if (!name.endsWith(".")) name += "."; RRset retVal = new RRset(); try { for (Certificate cert : certs) { int certRecordType = CERTRecord.PKIX; byte[] retData = null; X509Certificate xCert = null; try { // need to convert to cert container because this might be // a certificate with wrapped private key data final CertUtils.CertContainer cont = CertUtils.toCertContainer(cert.getData()); xCert = cont.getCert(); // check if this is a compliant certificate with the configured policy... if not, move on if (!isCertCompliantWithPolicy(xCert)) continue; retData = xCert.getEncoded(); } catch (CertificateConversionException e) { // probably not a Certificate... might be a URL } if (xCert == null) { // see if it's a URL try { retData = cert.getData(); URL url = new URL(new String(retData)); certRecordType = CERTRecord.URI; } catch (Exception e) { throw new DNSException( DNSError.newError(Rcode.SERVFAIL), "Failure while parsing CERT record data: " + e.getMessage(), e); } } int keyTag = 0; int alg = 0; if (xCert != null && xCert.getPublicKey() instanceof RSAKey) { RSAKey key = (RSAKey) xCert.getPublicKey(); byte[] modulus = key.getModulus().toByteArray(); keyTag = (modulus[modulus.length - 2] << 8) & 0xFF00; keyTag |= modulus[modulus.length - 1] & 0xFF; alg = 5; } CERTRecord rec = new CERTRecord( Name.fromString(name), DClass.IN, 86400L, certRecordType, keyTag, alg /*public key alg, RFC 4034*/, retData); retVal.addRR(rec); } } catch (Exception e) { throw new DNSException( DNSError.newError(Rcode.SERVFAIL), "Failure while parsing CERT record data: " + e.getMessage(), e); } // because of policy filtering, it's possible that we could have filtered out every cert // resulting in an empty RR set return (retVal.size() == 0) ? null : retVal; }