[JAVA] Signieren Sie XML mit Apache Santuario

Apache Santuario (XML-Sicherheit) (http://santuario.apache.org/) scheint de facto das Signaturzeichen für XML in Java zu sein.

1. Bereiten Sie Ihr Zertifikat und Ihren privaten Schlüssel vor

Zum Signieren benötigen Sie zunächst ein Zertifikat und einen privaten Schlüssel. Bitte bereiten Sie sich im Voraus vor. Als ich den privaten Schlüssel mit pem vorbereitet habe, wurde er nicht erkannt, daher werde ich den privaten Schlüssel im Format pkcs # 8 belassen. Es gibt vielleicht eine Möglichkeit, das PEM direkt zu lesen, aber hier werden wir den Schlüssel konvertieren.

$ openssl pkcs8 -in xxx.pem -topk8 -nocrypt -outform DER -out mypriv.key

2. Zertifikat und privaten Schlüssel lesen

Lesen Sie das Zertifikat und den privaten Schlüssel wie folgt: Oh, der Code verwendet auch Lombok.

public static X509Certificate loadCert(InputStream certFile) throws CertificateException {
    CertificateFactory cf = CertificateFactory.getInstance("X.509");

    return (X509Certificate)cf.generateCertificate(certFile);
}

public static PrivateKey loadPrivateKey(InputStream privateKey) throws IOException, GeneralSecurityException {
    val buf = readPrivateKey(privateKey);
    val keySPec = new PKCS8EncodedKeySpec(buf);
    	
    return KeyFactory.getInstance("RSA").generatePrivate(keySPec);
}

private static byte[] readPrivateKey(InputStream in) throws IOException {
    byte[] data = new byte[in.available()];
    in.read(data);
		
    return data;
}

3. Unterschreiben

Nachdem Sie Ihr Zertifikat und Ihren privaten Schlüssel bereit haben, signieren Sie das XML.

Erstellen Sie zuerst ein zu signierendes Objekt. Geben Sie den URI und den Signaturalgorithmus für das XML-Dokumentobjekt an, das beim Erstellen des Objekts und seiner Datei verarbeitet werden soll. Danach füge ich ein Element hinzu, um das ursprüngliche XML zu signieren.

val sig = new XMLSignature(doc, "file:/test.xml", XMLSignature.ALGO_ID_SIGNATURE_RSA_SHA256);
doc.getDocumentElement().appendChild(sig.getElement())

Übrigens test.xml

<?xml version="1.0" encoding="UTF-8"?>
<elem1>
  <elemt2>xxx</elem2>
</elem1>

Registrieren Sie als Nächstes den Resource Resolver. Dies ist der ResourceResolver, der dann das Objekt zum Abrufen der zu verdaulichen Elemente und des Inhalts einer anderen Datei ist. Der ResourceResolver-Code wird später erläutert.

Danach wird das Objekt für Transformationen festgelegt. ResourceResolver ist nur dafür verantwortlich, den Inhalt als Bytefolge abzurufen. Sie müssen kanonisieren, um den Digest aus den XML-Elementen zu erhalten. Transfomrs sind die Personen, die XML aus Bytes analysieren und kanonisieren.

Die erste Frage, die ich mir beim Signieren von XML gestellt habe, war, wie man es normalisiert. Wenn es nicht normalisiert wird, wird der Digest nicht korrekt ausgegeben. /www.w3.org/TR/xml-c14n11/), und transfomrs ist dafür verantwortlich.

Geben Sie diese Transformationen mit uri in addDocument an. Geben Sie null für Dateien an, die nicht konvertiert werden müssen.

sig.getSignedInfo().addResourceResolver(new MyResolver());

val transforms = new Transforms(kouseiBase);
transforms.addTransform(Transforms.TRANSFORM_ENVELOPED_SIGNATURE);
transforms.addTransform(Transforms.TRANSFORM_C14N_OMIT_COMMENTS);

sig.addDocument("#elem2", transforms, MessageDigestAlgorithm.ALGO_ID_DIGEST_SHA256);
sig.addDocument("somefile.txt", null, MessageDigestAlgorithm.ALGO_ID_DIGEST_SHA256);

Geben Sie anschließend das zu signierende Zertifikat und den privaten Schlüssel an. Die Signaturinformationen werden jetzt zum ersten Dokument hinzugefügt.

```java` sig.addKeyInfo(certificate); sig.addKeyInfo(certificate.getPublicKey()); sig.sign(privateKey);


 4. ResourceResolverSpi

 Verwenden Sie REsourceResolverSpi, um den URI aufzulösen. Es gibt zwei Methoden zur Implementierung: engineCanResolveURI und engineResolveURI. Ersteres prüft, ob der von addDocument angegebene URI von diesem Resolver aufgelöst werden kann. Letzteres ist eine Methode, um Inhalte von diesem Uri zu erhalten. Gibt ein Objekt namens XMLSignatureInput zurück.
 Ich löse eine ResourceResolverException aus, wenn eine Ausnahme auftritt, weiß aber nicht, wie ich sie richtig machen soll. Der Codekonstruktor hier ist veraltet.

```java
class MyResolver extends ResourceResolverSpi {
    @override
    public XMLSignatureInput engineResolveURI(ResourceResolverContext context) throws ResourceResolverException {
        val uri = context.attr.getValue();
        try {
            if (uri.equals("#elem2")) {
                val result = new XMLSignatureInput(new ByteArrayInputStream("<elemt2>xxx</elem2>".getBytes("utf-8")));
                result.setSourceURI(uri);
                result.setMIMEType("text/xml");

                return result;
            }
            if (uri.equals("somefile.txt")) {
                val result = new XMLSignatureInput(new ByteArrayInputStream(new FileInputStream(uri)));
                result.setSourceURI(uri);
                result.setMIMEType("application/octet-stream");
 
                return result;
            }
        } catch (Exception e) {
            throw new ResourceResolverException("generic.EmptyMessage", e, uri, context.baseUri);
        }
        return null;
    }

    @override
    public boolean engineCanResolveURI(ResourceResolverContext context) {
        val uri = context.attr.getValue();
        if (uri.equals("#elem2")) return true;
        if (uri.equals("somefile.txt")) return true;

        return false;
    }
}

5. Beenden

Sie können XML mit einem solchen Code signieren. Die XML-Signatur ist ziemlich verwirrend, aber die Bibliothek macht das Signieren relativ einfach. Es scheint jedoch, dass es nur wenige Dokumente gibt ...

Dewadewa

Recommended Posts

Signieren Sie XML mit Apache Santuario
Datenverarbeitung mit Apache Flink
Ich habe versucht, Apache Wicket zu verwenden
Ausgabe nach Excel mit Apache POI!