/** * Prueba que el sistema de firma masiva programatica no se queda colgado con ficheros mayores de * 7 megas. * * @throws Exception Cuando se produce algún error durante la prueba. */ @SuppressWarnings("static-method") @Test public void pruebaComprobacionPasoBase64() throws Exception { final byte[] data = getResource(DATA_FILE); Assert.assertFalse(AOUtil.isBase64(data)); Assert.assertTrue(AOUtil.isBase64(Base64.encode(data).getBytes())); }
private static String createSingleReqPresignNode(final TriphaseRequest triphaseRequest) { final StringBuilder sb = new StringBuilder("<req id=\""); // $NON-NLS-1$ sb.append(triphaseRequest.getRef()); sb.append("\" status=\""); // $NON-NLS-1$ if (triphaseRequest.isStatusOk()) { sb.append("OK\">"); // $NON-NLS-1$ for (final TriphaseSignDocumentRequest docReq : triphaseRequest) { sb.append("<doc docid=\"") .append(docReq.getId()) // $NON-NLS-1$ .append("\" cop=\"") .append(docReq.getCryptoOperation()) // $NON-NLS-1$ .append("\" sigfrmt=\"") .append(docReq.getSignatureFormat()) // $NON-NLS-1$ .append("\" mdalgo=\"") .append(docReq.getMessageDigestAlgorithm()) .append("\">") // $NON-NLS-1$ //$NON-NLS-2$ .append("<params>") .append(docReq.getParams() != null ? docReq.getParams() : "") .append("</params>") // $NON-NLS-1$ //$NON-NLS-2$ //$NON-NLS-3$ .append("<result>") // $NON-NLS-1$ .append(docReq.getPartialResult().toXMLConfig()) .append("</result></doc>"); // $NON-NLS-1$ } sb.append("</req>"); // $NON-NLS-1$ } else { String exceptionb64 = null; final Throwable t = triphaseRequest.getThrowable(); if (t != null) { final ByteArrayOutputStream baos = new ByteArrayOutputStream(); t.printStackTrace(new PrintWriter(baos)); exceptionb64 = Base64.encode(baos.toByteArray()); try { baos.close(); } catch (IOException e) { /* No hacemos nada */ } } if (exceptionb64 != null) { sb.append("KO\" exceptionb64=\"") // $NON-NLS-1$ .append(exceptionb64) .append("\" />"); // $NON-NLS-1$ } else { sb.append("KO\" />"); // $NON-NLS-1$ } } return sb.toString(); }
/** * Main. * * @param args * @throws Exception */ public static void main(final String[] args) throws Exception { // PDF de ejemplo final PdfReader reader = new PdfReader( AOUtil.getDataFromInputStream( ClassLoader.getSystemResourceAsStream("TEST_PDF.pdf") // $NON-NLS-1$ )); final ByteArrayOutputStream baos = new ByteArrayOutputStream(); final Calendar globalDate = new GregorianCalendar(); final PdfStamper stamper = new PdfStamper(reader, baos, globalDate); // // Datos a insertar como XMP // final BioMetadataSchema schema = new BioMetadataSchema(); // schema.addIso197947Data("HOLA".getBytes()); //$NON-NLS-1$ // // // Insertamos los datos en el XMP // final ByteArrayOutputStream os = new ByteArrayOutputStream(); // final XmpWriter xmp = new XmpWriter(os); // xmp.addRdfDescription(schema); // xmp.close(); // // // Insertamos el XMP en el PDF // stamper.setXmpMetadata(os.toByteArray()); final String sigDataBase64 = Base64.encode( AOUtil.getDataFromInputStream( ClassLoader.getSystemResourceAsStream("4df6ec6b6b5c7.jpg") // $NON-NLS-1$ )); final HashMap<String, String> moreInfo = new HashMap<String, String>(1); moreInfo.put("SignerBiometricSignatureData", sigDataBase64); // $NON-NLS-1$ moreInfo.put("SignerBiometricSignatureFormat", "ISO 19795-7"); // $NON-NLS-1$ //$NON-NLS-2$ moreInfo.put("SignerName", "Tom\u00E1s Garc\u00EDa-Mer\u00E1s"); // $NON-NLS-1$ //$NON-NLS-2$ stamper.setMoreInfo(moreInfo); stamper.close(globalDate); reader.close(); // Guardamos el resultado final File tmpFile = File.createTempFile("TESTXMP_", ".pdf"); // $NON-NLS-1$ //$NON-NLS-2$ final OutputStream fos = new FileOutputStream(tmpFile); fos.write(baos.toByteArray()); fos.flush(); fos.close(); }
/** * Prefirma (firma simple) en formato XAdES. * * @param data Datos a prefirmar * @param algorithm Algoritmo de firma * @param certChain Cadena de certificados del firmante * @param xParams Parámetros adicionales de la firma * @param op Operación específica de firma a realizar * @return Listado de prefirma XML * @throws NoSuchAlgorithmException Si el JRE no soporta algún algoritmo necesario. * @throws AOException Si ocurre cualquier otro error. * @throws SAXException Si hay problemas en el análisis XML. * @throws IOException Si hay problemas en el tratamiento de datos. * @throws ParserConfigurationException Si hay problemas con el analizador por defecto de XML. * @throws MarshalException Si hay problemas con el empaquetado XML. * @throws XMLSignatureException Si hay problemas en la propia firma XMLDSig. * @throws InvalidKeyException Si la clave proporcinoada no es válida. * @throws SignatureException Si hay problemas con la firma PKCS#1. * @throws XmlPreSignException Si hay un error en la pre-firma XAdES. */ public static XmlPreSignResult preSign( final byte[] data, final String algorithm, final Certificate[] certChain, final Properties xParams, final Op op) throws NoSuchAlgorithmException, AOException, SAXException, IOException, ParserConfigurationException, MarshalException, XMLSignatureException, InvalidKeyException, SignatureException, XmlPreSignException { if (data == null || data.length < 1) { throw new IllegalArgumentException( "Los datos a prefirmar no pueden ser nulos ni vacios"); //$NON-NLS-1$ } if (algorithm == null || "".equals(algorithm)) { // $NON-NLS-1$ throw new IllegalArgumentException( "El algoritmo de firma no puede ser nulo ni vacio"); //$NON-NLS-1$ } if (certChain == null || certChain.length < 1) { throw new IllegalArgumentException( "La cadena de certificados no puede ser nula y debe contener al menos un certificado" //$NON-NLS-1$ ); } // Miramos si la entrada es un XML que ya contenga firmas (almacenando los ID para luego // localizar cual es la firma // nueva y no confundirla con las antiguas), y si lo es cual es su codificacion con un // Document.getXmlEncoding() final List<String> previousSignaturesIds = new ArrayList<String>(); Document xml = null; String xmlEncoding = XML_DEFAULT_ENCODING; try { xml = DocumentBuilderFactory.newInstance() .newDocumentBuilder() .parse(new ByteArrayInputStream(data)); if (xml.getXmlEncoding() != null) { xmlEncoding = xml.getXmlEncoding(); } } catch (final Exception e) { Logger.getLogger("es.gob.afirma") .info( "El documento a firmar no es XML, por lo que no contiene firmas previas"); //$NON-NLS-1$//$NON-NLS-2$ } if (xml == null && (op == Op.COSIGN || op == Op.COUNTERSIGN)) { Logger.getLogger("es.gob.afirma") .severe("Solo se pueden cofirmar y contrafirmar firmas XML"); // $NON-NLS-1$//$NON-NLS-2$ throw new AOException( "Los datos introducidos no se corresponden con una firma XML"); //$NON-NLS-1$ } // Si los datos eran XML, comprobamos y almacenamos las firmas previas if (xml != null) { final Element rootElement = xml.getDocumentElement(); if (rootElement.getNodeName().endsWith(":" + AOXAdESSigner.SIGNATURE_TAG)) { // $NON-NLS-1$ final NamedNodeMap nnm = rootElement.getAttributes(); if (nnm != null) { final Node node = nnm.getNamedItem(XML_NODE_ID); if (node != null) { final String id = node.getNodeValue(); if (id != null) { previousSignaturesIds.add(id); } } } } else { final NodeList mainChildNodes = xml.getDocumentElement().getChildNodes(); for (int i = 0; i < mainChildNodes.getLength(); i++) { final Node currentNode = mainChildNodes.item(i); if (currentNode.getNodeType() == Node.ELEMENT_NODE && currentNode .getNodeName() .endsWith(":" + AOXAdESSigner.SIGNATURE_TAG)) { // $NON-NLS-1$ final NamedNodeMap nnm = currentNode.getAttributes(); if (nnm != null) { final Node node = nnm.getNamedItem(XML_NODE_ID); if (node != null) { final String id = node.getNodeValue(); if (id != null) { previousSignaturesIds.add(id); } } } } } } } // Generamos un par de claves para hacer la firma temporal, que despues sustituiremos por la // real final RSAPrivateKey prk = (RSAPrivateKey) generateKeyPair( ((RSAPublicKey) ((X509Certificate) certChain[0]).getPublicKey()) .getModulus() .bitLength()) .getPrivate(); final byte[] result; switch (op) { case SIGN: result = XAdESSigner.sign(data, algorithm, prk, certChain, xParams); break; case COSIGN: result = XAdESCoSigner.cosign(data, algorithm, prk, certChain, xParams); break; case COUNTERSIGN: final CounterSignTarget targets = xParams != null && CounterSignTarget.LEAFS .name() .equalsIgnoreCase(xParams.getProperty(COUNTERSIGN_TARGET_KEY)) ? CounterSignTarget.LEAFS : CounterSignTarget.TREE; result = XAdESCounterSigner.countersign(data, algorithm, targets, null, prk, certChain, xParams); break; default: throw new IllegalStateException( "No se puede dar una operacion no contemplada en el enumerado de operaciones" //$NON-NLS-1$ ); } // Cargamos el XML firmado en un String String xmlResult = new String(result, xmlEncoding); // Recuperamos los signed info que se han firmado final List<byte[]> signedInfos = XAdESTriPhaseSignerServerSide.getSignedInfos( result, certChain[0].getPublicKey(), previousSignaturesIds // Identificadores de firmas previas, para poder omitirlos ); // Ponemos un reemplazo en el XML en lugar de los PKCS#1 de las firmas generadas for (int i = 0; i < signedInfos.size(); i++) { final byte[] signedInfo = signedInfos.get(i); // Calculamos el valor PKCS#1 con la clave privada impostada, para conocer los valores que // debemos sustituir final Signature signature = Signature.getInstance(algorithm); signature.initSign(prk); signature.update(signedInfo); final String cleanSignatureValue = cleanBase64(Base64.encode(signature.sign())); // Buscamos el PKCS#1 en Base64 en el XML original y lo sustituimos por la cadena de reemplazo final String signValuePrefix = ">" + cleanSignatureValue.substring(0, NUM_CHARACTERS_TO_COMPARE); // $NON-NLS-1$ final int signValuePos = xmlResult.indexOf(signValuePrefix) + 1; final int signValueFinalPos = xmlResult.indexOf('<', signValuePos); final String pkcs1String = xmlResult.substring(signValuePos, signValueFinalPos); final String cleanPkcs1String = cleanBase64(pkcs1String); if (cleanSignatureValue.equals(cleanPkcs1String)) { xmlResult = xmlResult.replace( pkcs1String, REPLACEMENT_STRING.replace(REPLACEMENT_CODE, Integer.toString(i))); } } return new XmlPreSignResult(xmlResult.getBytes(xmlEncoding), signedInfos); }