コード例 #1
0
ファイル: BDoc.cpp プロジェクト: tixsys/esteid
/**
 * Adds document to the container. Documents can be removed from container only
 * after all signatures are removed.
 *
 * @param document a document, which is added to the container.
 * @throws BDocException exception is thrown if the document path is incorrect or document
 *         with same file name already exists. Also no document can be added if the
 *         container already has one or more signatures.
 */
void digidoc::BDoc::addDocument(const Document& document) throw(BDocException)
{
    if(signatures.size() == 0)
    {
        // Check that document file exists.
        if(!util::File::fileExists(document.getPath()))
        {
            THROW_BDOCEXCEPTION("Document file '%s' does not exist.", document.getPath().c_str());
        }

        // Check if document with same filename exists.
        std::string documentFileName = util::File::fileName(document.getPath());
        for(std::vector<Document>::const_iterator iter = documents.begin(); iter != documents.end(); iter++)
        {
            if(documentFileName.compare(util::File::fileName(iter->getPath())) == 0)
            {
                THROW_BDOCEXCEPTION("Document with same file name '%s' already exists '%s'.", document.getPath().c_str(), iter->getPath().c_str());
            }
        }

        documents.push_back(document);
    }
    else
    {
        THROW_BDOCEXCEPTION("Can not add document to container which has signatures, remove all signatures before adding new document.");
    }
}
コード例 #2
0
ファイル: BDoc.cpp プロジェクト: Krabi/idkaart_public
/**
 * Adds signature to the container.
 *
 * @param signature signature, which is added to the container.
 * @throws BDocException throws exception if there are no documents in container.
 */
void digidoc::BDoc::addSignature(const std::vector<unsigned char> &signature, Type profile) throw(BDocException)
{
    if(signature.empty())
        THROW_BDOCEXCEPTION("Empty signature object, can not add signature.");
    if(d->documents.empty())
        THROW_BDOCEXCEPTION("No documents in container, can not add signature.");

    std::string fileName = util::File::tempFileName();
    std::ofstream ofs(util::File::encodeName(fileName).c_str());
    ofs << "<?xml version=\"1.0\" encoding=\"UTF-8\" standalone=\"no\" ?>\n";
    for(std::vector<unsigned char>::const_iterator i = signature.begin(); i != signature.end(); ++i)
        ofs << *i;
    ofs.close();
    try
    {
        switch(profile)
        {
        case TM:
            d->signatures.push_back(new SignatureTM(fileName, *this));
            break;
        case BES:
            d->signatures.push_back(new SignatureBES(fileName, *this));
            break;
        }
    }
    catch(const Exception &)
    {
        THROW_BDOCEXCEPTION("Failed to add signature.");
    }
}
コード例 #3
0
ファイル: BDoc.cpp プロジェクト: Krabi/idkaart_public
/**
 * Adds signature to the container.
 *
 * @param signature signature, which is added to the container.
 * @throws BDocException throws exception if there are no documents in container.
 */
void digidoc::BDoc::addSignature(Signature* signature) throw(BDocException)
{
    if(!signature)
        THROW_BDOCEXCEPTION("Empty signature object, can not add signature.");
    if(d->documents.empty())
        THROW_BDOCEXCEPTION("No documents in container, can not add signature.");
    d->signatures.push_back(signature);
}
コード例 #4
0
ファイル: BDoc.cpp プロジェクト: Krabi/idkaart_public
/**
 * Removes document from container by document id. Documents can be
 * removed from container only after all signatures are removed.
 *
 * @param id document's id, which will be removed.
 * @throws BDocException throws exception if the document id is incorrect or there are
 *         one or more signatures.
 */
void digidoc::BDoc::removeDocument(unsigned int id) throw(BDocException)
{
    if(!d->signatures.empty())
        THROW_BDOCEXCEPTION("Can not remove document from container which has signatures, remove all signatures before removing document.");

    if(d->documents.size() > id)
        d->documents.erase(d->documents.begin() + id);
    else
        THROW_BDOCEXCEPTION("Incorrect document id %u, there are only %u documents in container.", id, d->documents.size());
}
コード例 #5
0
ファイル: BDoc.cpp プロジェクト: Krabi/idkaart_public
digidoc::BDoc::BDoc(const std::string &path) throw(IOException, BDocException)
 : d(new BDocPrivate)
{
    THROW_BDOCEXCEPTION("BDOC 1 container is unsupported.");
    std::auto_ptr<ISerialize> serializer(new ZipSerialize(path));
    readFrom(serializer);
}
コード例 #6
0
ファイル: BDoc.cpp プロジェクト: Krabi/idkaart_public
/**
 * Reads and parses container mimetype. Checks that the mimetype is supported.
 *
 * @param path path to container directory.
 * @throws IOException exception is thrown if there was error reading mimetype file from disk.
 * @throws BDocException exception is thrown if the parsed mimetype is incorrect.
 */
void digidoc::BDoc::readMimetype(const std::string &path) throw(IOException, BDocException)
{
    DEBUG("BDoc::readMimetype(path = '%s')", path.c_str());
    // Read mimetype from file.
    std::string fileName = util::File::path(path, "mimetype");
    std::ifstream ifs(util::File::encodeName(fileName).c_str(), std::ios::binary);

    unsigned char bom[] = { 0, 0, 0 };
    ifs.read((char*)bom, sizeof(bom));
    // Contains UTF-16 BOM
    if((bom[0] == 0xFF && bom[1] == 0xEF) ||
       (bom[0] == 0xEF && bom[1] == 0xFF))
        THROW_IOEXCEPTION("Mimetype file must be UTF-8 format.", fileName.c_str());
    // does not contain UTF-8 BOM reset pos
    if(!(bom[0] == 0xEF && bom[1] == 0xBB && bom[2] == 0xBF))
        ifs.seekg(0, std::ios::beg);

    std::string mimetype;
    ifs >> mimetype;
    ifs.close();

    if(ifs.fail())
        THROW_IOEXCEPTION("Failed to read mimetype file from '%s'.", fileName.c_str());

    // Check that mimetype version is correct.
    DEBUG("mimetype = '%s'", mimetype.c_str());
    if(getMimeType() != mimetype)
        THROW_BDOCEXCEPTION("Incorrect mimetype '%s', expecting '%s'", mimetype.c_str(), getMimeType().c_str());
}
コード例 #7
0
ファイル: BDoc.cpp プロジェクト: tixsys/esteid
/**
 * Returns signature referenced by signature id.
 *
 * @param id signature id.
 * @return returns signature referenced by signature id.
 * @throws BDocException throws exception if the signature id is incorrect.
 */
const digidoc::Signature* digidoc::BDoc::getSignature(unsigned int id) const throw(BDocException)
{
    if( id >= signatures.size() )
    {
        THROW_BDOCEXCEPTION("Incorrect signature id %u, there are only %u signatures in container.", id, signatures.size());
    }

    return signatures[id];
}
コード例 #8
0
ファイル: BDoc.cpp プロジェクト: tixsys/esteid
/**
 * Returns document referenced by document id.
 *
 * @param id document id.
 * @return returns document referenced by document id.
 * @throws BDocException throws exception if the document id is incorrect.
 */
digidoc::Document digidoc::BDoc::getDocument(unsigned int id) const throw(BDocException)
{
    if( id >= documents.size() )
    {
        THROW_BDOCEXCEPTION("Incorrect document id %u, there are only %u documents in container.", id, documents.size());
    }

    return documents[id];
}
コード例 #9
0
ファイル: BDoc.cpp プロジェクト: Krabi/idkaart_public
/**
 * Removes signature from container by signature id.
 *
 * @param id signature's id, which will be removed.
 * @throws BDocException throws exception if the signature id is incorrect.
 */
void digidoc::BDoc::removeSignature(unsigned int id) throw(BDocException)
{
    if(d->signatures.size() > id)
    {
        std::vector<Signature*>::iterator it = (d->signatures.begin() + id);
        delete *it;
        d->signatures.erase(it);
    }
    else
        THROW_BDOCEXCEPTION("Incorrect signature id %u, there are only %u signatures in container.", id, d->signatures.size());
}
コード例 #10
0
ファイル: BDoc.cpp プロジェクト: tixsys/esteid
/**
 * Saves the container using the <code>serializer</code> implementation provided in
 * <code>readFrom()</code> method.
 *
 * @throws IOException is thrown if there was a failure saving BDOC container. For example added
 *         document does not exist.
 * @throws BDocException is thrown if BDoc class is not correctly initialized.
 */
void digidoc::BDoc::save() throw(IOException, BDocException)
{
    // Check that serializer is provided.
    if(serializer.get() == NULL)
    {
        THROW_BDOCEXCEPTION("You can not use save() method if you didn't open a container with readFrom() method. Use saveTo() method in case of new a BDoc container.");
    }

    // Check that at least one document is in container.
    if( documents.empty() )
    {
        THROW_BDOCEXCEPTION("Can not save, BDoc container is empty.");
    }

    // Create new container.
    serializer->create();

    // Create mimetype file and add it to container.
    serializer->addFile("mimetype", createMimetype());

    // Create manifest file and add it to container.
    // NB! Don't change the order of signatures in list after manifest is created,
    //     otherwise manifest has incorrect signature mimetypes.
    serializer->addFile("META-INF/manifest.xml", createManifest());

    // Add all documents to container.
    for(std::vector<Document>::const_iterator iter = documents.begin(); iter != documents.end(); iter++)
    {
        serializer->addFile(util::File::fileName(iter->getPath()), iter->getPath());
    }

    // Add all signatures to container.
    unsigned int i = 0;
    for(std::vector<Signature*>::const_iterator iter = signatures.begin(); iter != signatures.end(); iter++)
    {
        serializer->addFile(util::String::format("META-INF/signature%u.xml", i++), (*iter)->saveToXml());
    }

    // Save container.
    serializer->save();
}
コード例 #11
0
ファイル: BDoc.cpp プロジェクト: Krabi/idkaart_public
/**
 * Signs all documents in container.
 *
 * @param signer signer implementation.
 * @param profile signature profile (e.g. BES, TM).
 * @throws BDocException exception is throws if signing the BDCO container failed.
 */
void digidoc::BDoc::sign(Signer* signer, Type profile) throw(BDocException)
{
    if (!signer)
        THROW_BDOCEXCEPTION("Null pointer in digidoc::BDoc::sign");

    DEBUG("sign(signer = %p, profile=%d)", signer, profile);

    // Create signature by type.
    Signature* signature = NULL;
    switch(profile)
    {
    case BES:
        signature = new SignatureBES(newSignatureId(), *this);
        break;
    case TM:
        signature = new SignatureTM(newSignatureId(), *this);
        break;
    default:
        THROW_BDOCEXCEPTION("Unknown signature profile: %d", profile);
        break;
    }

    try
    {
        // Finalize the signature by calculating signature.
        signature->sign(signer);
    }
    catch(const SignatureException& e)
    {
        delete signature;
        THROW_BDOCEXCEPTION_CAUSE(e, "Failed to sign BDOC container.");
    }
    catch(const SignException& e)
    {
        delete signature;
        THROW_BDOCEXCEPTION_CAUSE(e, "Failed to sign BDOC container.");
    }

    // Add the created signature to the signatures list.
    addSignature(signature);
}
コード例 #12
0
ファイル: BDoc.cpp プロジェクト: tixsys/esteid
/**
 * Adds signature to the container.
 *
 * @param signature signature, which is added to the container.
 * @throws BDocException throws exception if there are no documents in container.
 */
void digidoc::BDoc::addSignature(Signature* signature) throw(BDocException)
{
    assert(signature != NULL); // why did you do this?

    if(!documents.empty())
    {
        signatures.push_back(signature);
    }
    else
    {
        THROW_BDOCEXCEPTION("No documents in container, can not add signature.");
    }
}
コード例 #13
0
ファイル: BDoc.cpp プロジェクト: tixsys/esteid
/**
 * Reads and parses container mimetype. Checks that the mimetype is supported.
 *
 * @param path path to container directory.
 * @throws IOException exception is thrown if there was error reading mimetype file from disk.
 * @throws BDocException exception is thrown if the parsed mimetype is incorrect.
 */
void digidoc::BDoc::readMimetype(std::string path) throw(IOException, BDocException)
{
    DEBUG("BDoc::readMimetype(path = '%s')", path.c_str());
    // Read mimetype from file.
    std::string fileName = util::File::path(path, "mimetype");
    std::ifstream ifs(util::File::fstreamName(fileName).c_str());
    std::string mimetype;
    ifs >> mimetype;
    ifs.close();

    if(ifs.fail())
    {
        THROW_IOEXCEPTION("Failed to read mimetype file from '%s'.", fileName.c_str());
    }

    // Check that mimetype version is correct.
    DEBUG("mimetype = '%s'", mimetype.c_str());
    if(getMimeType().compare(mimetype) != 0)
    {
        THROW_BDOCEXCEPTION("Incorrect mimetype '%s', expecting '%s'", mimetype.c_str(), getMimeType().c_str());
    }
}
コード例 #14
0
ファイル: BDoc.cpp プロジェクト: tixsys/esteid
/**
 * Signs all documents in container.
 *
 * @param signer signer implementation.
 * @param profile signature profile (e.g. BES, TM).
 * @throws BDocException exception is throws if signing the BDCO container failed.
 */
void digidoc::BDoc::sign(Signer* signer, Signature::Type profile) throw(BDocException)
{
    if (signer == NULL)
    {
        THROW_BDOCEXCEPTION("Null pointer in digidoc::BDoc::sign");
    }

    DEBUG("sign(signer = 0x%X, profile=%d)", (unsigned int)signer, profile);

    // Create signature by type.
    Signature* signature = NULL;
    if(profile == Signature::BES)
    {
        signature = new SignatureBES(*this);
    }
    else if(profile == Signature::TM)
    {
        signature = new SignatureTM(*this);
    }
	else if(profile == Signature::MOBILE)
	{
		try {
			signature = new SignatureMobile( signer->signaturePath(), *this);
		} catch(const Exception& e) {
			THROW_BDOCEXCEPTION_CAUSE(e, "MobileSignature");
		}
		addSignature( signature );
		return;
	}
	else
    {
        THROW_BDOCEXCEPTION("Unknown signature profile: %d", profile);
    }

    // Calculate digests for the documents and add these to the signature reference.
    for(std::vector<Document>::iterator iter = documents.begin(); iter != documents.end(); iter++)
    {
        try
        {
            DEBUG("Adding document '%s', '%s' to the signature references.", iter->getPath().c_str(), iter->getMediaType().c_str());
            // URIs must encode non-ASCII characters in the format %HH where HH is the hex representation of the character
            std::string uri = std::string("/") + digidoc::util::String::toUriFormat(digidoc::util::File::fileName(iter->getPath()));
            std::auto_ptr<Digest> calc = Digest::create();
            std::vector<unsigned char> digest = iter->calcDigest(calc.get());
            DEBUGMEM("digest", &digest[0], digest.size());
            signature->addReference(uri, calc->getUri(), digest);
        }
        catch(const Exception& e)
        {
            delete signature;
            THROW_BDOCEXCEPTION_CAUSE(e, "Failed to calculate digests for document '%s'.", iter->getPath().c_str());
        }
    }

    try
    {
        // Finalize the signature by calculating signature.
        signature->sign(signer);
    }
    catch(const SignatureException& e)
    {
        delete signature;
        THROW_BDOCEXCEPTION_CAUSE(e, "Failed to sign BDOC container.");
    }
    catch(const SignException& e)
    {
        delete signature;
        THROW_BDOCEXCEPTION_CAUSE(e, "Failed to sign BDOC container.");
    }

    // Add the created signature to the signatures list.
    addSignature(signature);
}
コード例 #15
0
ファイル: BDoc.cpp プロジェクト: tixsys/esteid
/**
 * Parses manifest file and checks that files described in manifest exist, also
 * checks that no extra file do exist that are not described in manifest.xml.
 *
 * Note: If non-ascii characters are present in XML data, we depend on the LANG variable to be set properly 
 * (see iconv --list for the list of supported encoding values for libiconv).
 *
 * @param path directory on disk of the BDOC container.
 * @throws IOException exception is thrown if the manifest.xml file parsing failed.
 * @throws BDocException
 */
void digidoc::BDoc::parseManifestAndLoadFiles(std::string path) throw(IOException, BDocException)
{
    DEBUG("BDoc::readManifest(path = '%s')", path.c_str());

    try
    {
        // Parse manifest file.
        std::string fileName = util::File::path(path, "META-INF/manifest.xml");
        xml_schema::Properties properties;
        properties.schema_location(MANIFEST_NAMESPACE, Conf::getInstance()->getManifestXsdPath());
        std::auto_ptr<manifest::Manifest> manifest(manifest::manifest(fileName, xml_schema::Flags::dont_initialize, properties));

        // Extract and validate file list from manifest.
        std::set<std::string> manifestFiles;
        bool mimetypeChecked = false;
        for(manifest::Manifest::File_entrySequence::const_iterator iter = manifest->file_entry().begin(); iter != manifest->file_entry().end(); iter++)
        {
            DEBUG("full_path = '%s', media_type = '%s'", iter->full_path().c_str(), iter->media_type().c_str());
            // Check container mimetype.
            if(std::string("/").compare(iter->full_path()) == 0)
            {
                if(mimetypeChecked)
                {
                    THROW_BDOCEXCEPTION("Manifest has more than one container media type defined.");
                }

                if(getMimeType().compare(iter->media_type()) != 0)
                {
                    THROW_BDOCEXCEPTION("Manifest has incorrect BDCO container media type defined '%s', expecting '%s'.", iter->media_type().c_str(), getMimeType().c_str());
                }

                DEBUG("BDOC mimetype OK");
                mimetypeChecked = true;
                continue;
            }

            // Check that file reference is not defined already and add relative file reference to set.
            if(manifestFiles.find(iter->full_path()) != manifestFiles.end())
            {
                THROW_BDOCEXCEPTION("Manifest multiple entries defined for file '%s'.", iter->media_type().c_str());
            }
            manifestFiles.insert(iter->full_path());

            // Add document to documents list.
            if(iter->full_path().find_first_of("/") == std::string::npos)
            {
                if(!util::File::fileExists(util::File::path(path, iter->full_path())))
                {
                    THROW_BDOCEXCEPTION("File described in manifest '%s' does not exist in BDOC container.", iter->full_path().c_str());
                }
                documents.push_back(Document(util::File::path(path, iter->full_path()), iter->media_type()));
                continue;
            }

            // Add signature to signatures list.
            DEBUG("%s :: %u", iter->full_path().c_str(), iter->full_path().find_first_of("META-INF/"));
            std::string signatureFileName = (iter->full_path().substr((iter->full_path().find('/'))+1));

            if(iter->full_path().find_first_of("META-INF/") == 0)
            {
                DEBUG("signature filename :: '%s'", signatureFileName.c_str());

                if(signatureFileName.find_first_of("/") != std::string::npos)
                {
                    THROW_BDOCEXCEPTION("Unexpected file described in manifest '%s'.", iter->full_path().c_str());
                }

                if(!util::File::fileExists(util::File::path(util::File::path(path, "META-INF"), signatureFileName)))
                {
                    THROW_BDOCEXCEPTION("File described in manifest '%s' does not exist in BDOC container.", iter->full_path().c_str());
                }

                std::string signaturePath = util::File::path(util::File::path(path, "META-INF"), signatureFileName);    

                try
                {
                    if(SignatureBES::MEDIA_TYPE == iter->media_type())
                    {
                        signatures.push_back(new SignatureBES(signaturePath, *this));
                    }
                    else if(SignatureTM::MEDIA_TYPE == iter->media_type())
                    {
                        signatures.push_back(new SignatureTM(signaturePath, *this));
                    }
                    else
                    {
                        THROW_BDOCEXCEPTION("Unknown signature media type '%s'.", iter->media_type().c_str());
                    }
                }
                catch(const SignatureException& e)
                {
                    THROW_BDOCEXCEPTION_CAUSE(e, "Failed to parse signature '%s', type '%s'.", signaturePath.c_str(), iter->media_type().c_str());
                }

                continue;
            }

            // Found unexpected file description in manifest.
            THROW_BDOCEXCEPTION("Unexpected file description found in container manifest.");
        }

        if(!mimetypeChecked)
        {
            THROW_BDOCEXCEPTION("Manifest file does not have BDOC media type described.");
        }

        // Check that there are no unexpected files in container.
        std::vector<std::string> containerFiles = util::File::listFiles(path, true, true, true);
        for(std::vector<std::string>::const_iterator iter = containerFiles.begin(); iter != containerFiles.end(); iter++)
        {

            std::string containerFile = *iter;
            if(std::string("mimetype").compare(containerFile) == 0
            || std::string("META-INF/manifest.xml").compare(containerFile) == 0)
            {
                continue;
            }

            std::replace(containerFile.begin(), containerFile.end(), '\\', '/');
            if(manifestFiles.find(containerFile) == manifestFiles.end())
            {
                THROW_BDOCEXCEPTION("File '%s' found in BDOC container is not described in manifest.", containerFile.c_str());
            }
        }
    }
    catch(const xml_schema::Exception& e)
    {
        std::ostringstream oss;
        oss << e;
        THROW_IOEXCEPTION("Failed to parse manifest XML: %s", oss.str().c_str());
    }
}
コード例 #16
0
ファイル: BDoc.cpp プロジェクト: Krabi/idkaart_public
/**
 * Initialize BDOC container.
 */
digidoc::BDoc::BDoc()
 : d(new BDocPrivate)
{
    THROW_BDOCEXCEPTION("BDOC 1 container is unsupported.");
}