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

org.xipki.security.pkcs12.P12XdhMacContentSignerBuilder Maven / Gradle / Ivy

/*
 *
 * Copyright (c) 2013 - 2020 Lijun Liao
 *
 * Licensed under the Apache License, Version 2.0 (the "License");
 * you may not use this file except in compliance with the License.
 * You may obtain a copy of the License at
 *
 * http://www.apache.org/licenses/LICENSE-2.0
 *
 * Unless required by applicable law or agreed to in writing, software
 * distributed under the License is distributed on an "AS IS" BASIS,
 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
 * See the License for the specific language governing permissions and
 * limitations under the License.
 */

package org.xipki.security.pkcs12;

import static org.xipki.util.Args.notNull;
import static org.xipki.util.Args.positive;

import java.io.IOException;
import java.security.InvalidKeyException;
import java.security.NoSuchAlgorithmException;
import java.security.NoSuchProviderException;
import java.security.PrivateKey;
import java.security.PublicKey;
import java.util.ArrayList;
import java.util.Arrays;
import java.util.List;

import javax.crypto.KeyAgreement;
import javax.crypto.SecretKey;
import javax.crypto.spec.SecretKeySpec;

import org.bouncycastle.asn1.ASN1EncodableVector;
import org.bouncycastle.asn1.DEROctetString;
import org.bouncycastle.asn1.DERSequence;
import org.bouncycastle.asn1.pkcs.IssuerAndSerialNumber;
import org.bouncycastle.asn1.x500.X500Name;
import org.bouncycastle.asn1.x509.AlgorithmIdentifier;
import org.bouncycastle.operator.RuntimeOperatorException;
import org.xipki.security.ConcurrentContentSigner;
import org.xipki.security.DfltConcurrentContentSigner;
import org.xipki.security.EdECConstants;
import org.xipki.security.HashAlgo;
import org.xipki.security.ObjectIdentifiers.Xipki;
import org.xipki.security.X509Cert;
import org.xipki.security.XiContentSigner;
import org.xipki.security.XiSecurityException;

/**
 * Builder of PKCS#12 XDH (e.g. X25519, X448) MAC signer.
 *s
 * @author Lijun Liao
 */

public class P12XdhMacContentSignerBuilder {

  private static class XdhMacContentSigner extends HmacContentSigner {

    private final byte[] prefix;

    private final int hashLen;

    private XdhMacContentSigner(HashAlgo hashAlgo, AlgorithmIdentifier algorithmIdentifier,
        SecretKey signingKey, IssuerAndSerialNumber peerIssuerAndSerial)
            throws XiSecurityException {
      super(hashAlgo, algorithmIdentifier, signingKey);
      this.hashLen = hashAlgo.getLength();

      ASN1EncodableVector vec = new ASN1EncodableVector();
      if (peerIssuerAndSerial != null) {
        vec.add(peerIssuerAndSerial);
      }

      vec.add(new DEROctetString(new byte[hashLen]));

      byte[] encodedSig;
      try {
        encodedSig = new DERSequence(vec).getEncoded();
      } catch (IOException ex) {
        throw new XiSecurityException(
            "exception initializing ContentSigner: " + ex.getMessage(), ex);
      }
      this.prefix = Arrays.copyOfRange(encodedSig, 0, encodedSig.length - hashLen);
    }

    /**
     * Signature has the following format.
     * 
     * DhSigStatic ::= SEQUENCE {
     *   issuerAndSerial IssuerAndSerialNumber OPTIONAL,
     *   hashValue       MessageDigest
     * }
     *
     * MessageDigest ::= OCTET STRING
     * 
*/ @Override public byte[] getSignature() { byte[] hashValue = super.getSignature(); if (hashValue.length != hashLen) { throw new RuntimeOperatorException( "exception obtaining signature: invalid signature length"); } byte[] sigValue = new byte[prefix.length + hashLen]; System.arraycopy(prefix, 0, sigValue, 0, prefix.length); System.arraycopy(hashValue, 0, sigValue, prefix.length, hashLen); return sigValue; } } // class XdhMacContentSigner private SecretKey key; private AlgorithmIdentifier algId; private HashAlgo hash; private IssuerAndSerialNumber peerIssuerAndSerial; private final PublicKey publicKey; private final X509Cert[] certificateChain; public P12XdhMacContentSignerBuilder(X509Cert peerCert, PrivateKey privateKey, PublicKey publicKey) throws XiSecurityException { notNull(privateKey, "privateKey"); notNull(peerCert, "peerCert"); this.publicKey = notNull(publicKey, "publicKey"); this.certificateChain = null; init(privateKey, peerCert); } public P12XdhMacContentSignerBuilder(KeypairWithCert keypairWithCert, X509Cert peerCert) throws XiSecurityException { notNull(keypairWithCert, "keypairWithCert"); notNull(peerCert, "peerCert"); this.publicKey = keypairWithCert.getPublicKey(); this.certificateChain = keypairWithCert.getCertificateChain(); init(keypairWithCert.getKey(), peerCert); } private void init(PrivateKey privateKey, X509Cert peerCert) throws XiSecurityException { String algorithm = privateKey.getAlgorithm(); if (EdECConstants.X25519.equalsIgnoreCase(algorithm)) { this.algId = new AlgorithmIdentifier(Xipki.id_alg_dhPop_x25519_sha256); this.hash = HashAlgo.SHA256; } else if (EdECConstants.X448.equalsIgnoreCase(algorithm)) { this.algId = new AlgorithmIdentifier(Xipki.id_alg_dhPop_x448_sha512); this.hash = HashAlgo.SHA512; } else { throw new IllegalArgumentException("unsupported key.getAlgorithm(): " + algorithm); } PublicKey peerPubKey = peerCert.getPublicKey(); if (!algorithm.equalsIgnoreCase(peerPubKey.getAlgorithm())) { throw new IllegalArgumentException("peerCert and key does not match"); } // compute the secret key byte[] zz; try { KeyAgreement keyAgreement = KeyAgreement.getInstance(algorithm, "BC"); keyAgreement.init(privateKey); keyAgreement.doPhase(peerPubKey, true); zz = keyAgreement.generateSecret(); } catch (NoSuchAlgorithmException | NoSuchProviderException | InvalidKeyException | IllegalStateException ex) { throw new XiSecurityException("KeyChange error", ex); } // as defined in RFC 6955, raw hash algorithm is used as KDF byte[] leadingInfo; byte[] trailingInfo; try { // LeadingInfo := Subject Distinguished Name from certificate leadingInfo = peerCert.getSubject().getEncoded(); // TrailingInfo ::= Issuer Distinguished Name from certificate trailingInfo = peerCert.getIssuer().getEncoded(); } catch (IOException ex) { throw new XiSecurityException("error encoding certificate", ex); } byte[] k = this.hash.hash(leadingInfo, zz, trailingInfo); this.key = new SecretKeySpec(k, "HMAC-" + this.hash.getName()); this.peerIssuerAndSerial = new IssuerAndSerialNumber(X500Name.getInstance(trailingInfo), peerCert.getSerialNumber()); } // method init public ConcurrentContentSigner createSigner(int parallelism) throws XiSecurityException { positive(parallelism, "parallelism"); List signers = new ArrayList<>(parallelism); for (int i = 0; i < parallelism; i++) { XiContentSigner signer = new XdhMacContentSigner(hash, algId, key, peerIssuerAndSerial); signers.add(signer); } final boolean mac = true; DfltConcurrentContentSigner concurrentSigner; try { concurrentSigner = new DfltConcurrentContentSigner(mac, signers, key); } catch (NoSuchAlgorithmException ex) { throw new XiSecurityException(ex.getMessage(), ex); } concurrentSigner.setSha1DigestOfMacKey(HashAlgo.SHA1.hash(key.getEncoded())); if (certificateChain != null) { concurrentSigner.setCertificateChain(certificateChain); } else { concurrentSigner.setPublicKey(publicKey); } return concurrentSigner; } // method createSigner }




© 2015 - 2025 Weber Informatics LLC | Privacy Policy