diff --git a/SOURCES/poppler-0.66.0-nss.patch b/SOURCES/poppler-0.66.0-nss.patch new file mode 100644 index 0000000..001e528 --- /dev/null +++ b/SOURCES/poppler-0.66.0-nss.patch @@ -0,0 +1,1072 @@ +diff --git a/config.h.cmake b/config.h.cmake +index 7989cbfb..6f5e147e 100644 +--- a/config.h.cmake ++++ b/config.h.cmake +@@ -24,9 +24,6 @@ + /* Use zlib instead of builtin zlib decoder to uncompress flate streams. */ + #cmakedefine ENABLE_ZLIB_UNCOMPRESS 1 + +-/* Build against libnss3 for digital signature validation */ +-#cmakedefine ENABLE_NSS3 1 +- + /* Use cairo for rendering. */ + #cmakedefine HAVE_CAIRO 1 + +diff --git a/poppler/Decrypt.cc b/poppler/Decrypt.cc +index 16476f4f..9f4adda3 100644 +--- a/poppler/Decrypt.cc ++++ b/poppler/Decrypt.cc +@@ -39,17 +39,33 @@ + #include "goo/grandom.h" + #include "Decrypt.h" + #include "Error.h" +- ++#ifdef ENABLE_NSS3 ++#include ++#include ++#include ++#endif ++ ++#ifdef ENABLE_NSS3 ++static PK11Context *rc4InitContext(const Guchar *key, int keyLen); ++static Guchar rc4DecryptByte(PK11Context *context, Guchar c); ++#else + static void rc4InitKey(Guchar *key, int keyLen, Guchar *state); + static Guchar rc4DecryptByte(Guchar *state, Guchar *x, Guchar *y, Guchar c); ++#endif + + static GBool aesReadBlock(Stream *str, Guchar *in, GBool addPadding); + ++#ifdef ENABLE_NSS3 ++static PK11Context *aesInitContext(Guchar *in, Guchar *objKey, int objKeyLength, GBool decrypt); ++#else + static void aesKeyExpansion(DecryptAESState *s, Guchar *objKey, int objKeyLen, GBool decrypt); ++#endif + static void aesEncryptBlock(DecryptAESState *s, Guchar *in); + static void aesDecryptBlock(DecryptAESState *s, Guchar *in, GBool last); + ++#ifndef ENABLE_NSS3 + static void aes256KeyExpansion(DecryptAES256State *s, Guchar *objKey, int objKeyLen, GBool decrypt); ++#endif + static void aes256EncryptBlock(DecryptAES256State *s, Guchar *in); + static void aes256DecryptBlock(DecryptAES256State *s, Guchar *in, GBool last); + +@@ -70,6 +86,31 @@ static const Guchar passwordPad[32] = { + // Decrypt + //------------------------------------------------------------------------ + ++#ifdef ENABLE_NSS3 ++static void shutdownNSS() ++{ ++ if (NSS_Shutdown() != SECSuccess) { ++ error(errInternal, -1, "NSS shutdown failed: {0:s}", ++ PR_ErrorToString(PR_GetError(), PR_LANGUAGE_I_DEFAULT)); ++ } ++} ++ ++static GBool initNSS() { ++ if (NSS_IsInitialized()) { ++ return gTrue; ++ } else { ++ if (NSS_NoDB_Init(".") != SECSuccess) { ++ error(errInternal, -1, "NSS initialization failed: {0:s}", ++ PR_ErrorToString(PR_GetError(), PR_LANGUAGE_I_DEFAULT)); ++ return gFalse; ++ } else { ++ atexit(shutdownNSS); ++ return gTrue; ++ } ++ } ++} ++#endif ++ + GBool Decrypt::makeFileKey(int encVersion, int encRevision, int keyLength, + GooString *ownerKey, GooString *userKey, + GooString *ownerEnc, GooString *userEnc, +@@ -80,13 +121,21 @@ GBool Decrypt::makeFileKey(int encVersio + DecryptAES256State state; + Guchar test[127 + 56], test2[32]; + GooString *userPassword2; +- Guchar fState[256]; + Guchar tmpKey[16]; +- Guchar fx, fy; + int len, i, j; ++#ifdef ENABLE_NSS3 ++ PK11Context *rc4Context; ++#else ++ Guchar fState[256]; ++ Guchar fx, fy; ++#endif + + *ownerPasswordOk = gFalse; + ++#ifdef ENABLE_NSS3 ++ initNSS(); ++#endif ++ + if (encRevision == 5 || encRevision == 6) { + + // check the owner password +@@ -115,15 +164,27 @@ GBool Decrypt::makeFileKey(int encVersio + //test contains the initial SHA-256 hash input K. + revision6Hash(ownerPassword, test, userKey->getCString()); + } ++#ifndef ENABLE_NSS3 + aes256KeyExpansion(&state, test, 32, gTrue); ++#endif + for (i = 0; i < 16; ++i) { + state.cbc[i] = 0; + } ++#ifdef ENABLE_NSS3 ++ state.context = aesInitContext(state.cbc, test, 32, gTrue); ++ if (state.context) { ++#endif + aes256DecryptBlock(&state, (Guchar *)ownerEnc->getCString(), gFalse); + memcpy(fileKey, state.buf, 16); + aes256DecryptBlock(&state, (Guchar *)ownerEnc->getCString() + 16, + gFalse); + memcpy(fileKey + 16, state.buf, 16); ++#ifdef ENABLE_NSS3 ++ PK11_DestroyContext(state.context, PR_TRUE); ++ } else { ++ return gFalse; ++ } ++#endif + + *ownerPasswordOk = gTrue; + return gTrue; +@@ -156,15 +217,27 @@ GBool Decrypt::makeFileKey(int encVersio + //user key is not used in computing intermediate user key. + revision6Hash(userPassword, test, nullptr); + } ++#ifndef ENABLE_NSS3 + aes256KeyExpansion(&state, test, 32, gTrue); ++#endif + for (i = 0; i < 16; ++i) { + state.cbc[i] = 0; + } ++#ifdef ENABLE_NSS3 ++ state.context = aesInitContext(state.cbc, test, 32, gTrue); ++ if (state.context) { ++#endif + aes256DecryptBlock(&state, (Guchar *)userEnc->getCString(), gFalse); + memcpy(fileKey, state.buf, 16); + aes256DecryptBlock(&state, (Guchar *)userEnc->getCString() + 16, + gFalse); + memcpy(fileKey + 16, state.buf, 16); ++#ifdef ENABLE_NSS3 ++ PK11_DestroyContext(state.context, PR_TRUE); ++ } else { ++ return gFalse; ++ } ++#endif + + return gTrue; + } +@@ -189,22 +262,41 @@ GBool Decrypt::makeFileKey(int encVersio + } + } + if (encRevision == 2) { ++#ifdef ENABLE_NSS3 ++ rc4Context = rc4InitContext(test, keyLength); ++ if (rc4Context) { ++ for (i = 0; i < 32; ++i) ++ test2[i] = rc4DecryptByte(rc4Context, ownerKey->getChar(i)); ++ PK11_DestroyContext(rc4Context, PR_TRUE); ++ } ++#else + rc4InitKey(test, keyLength, fState); + fx = fy = 0; + for (i = 0; i < 32; ++i) { + test2[i] = rc4DecryptByte(fState, &fx, &fy, ownerKey->getChar(i)); + } ++#endif + } else { + memcpy(test2, ownerKey->getCString(), 32); + for (i = 19; i >= 0; --i) { + for (j = 0; j < keyLength; ++j) { + tmpKey[j] = test[j] ^ i; + } ++#ifdef ENABLE_NSS3 ++ rc4Context = rc4InitContext(tmpKey, keyLength); ++ if (rc4Context) { ++ for (j = 0; j < 32; ++j) { ++ test2[j] = rc4DecryptByte(rc4Context, test2[j]); ++ } ++ PK11_DestroyContext(rc4Context, PR_TRUE); ++ } ++#else + rc4InitKey(tmpKey, keyLength, fState); + fx = fy = 0; + for (j = 0; j < 32; ++j) { + test2[j] = rc4DecryptByte(fState, &fx, &fy, test2[j]); + } ++#endif + } + } + userPassword2 = new GooString((char *)test2, 32); +@@ -232,11 +324,15 @@ GBool Decrypt::makeFileKey2(int encVersi + GBool encryptMetadata) { + Guchar *buf; + Guchar test[32]; +- Guchar fState[256]; + Guchar tmpKey[16]; +- Guchar fx, fy; + int len, i, j; +- GBool ok; ++ GBool ok = gTrue; ++#ifdef ENABLE_NSS3 ++ PK11Context *rc4Context; ++#else ++ Guchar fState[256]; ++ Guchar fx, fy; ++#endif + + // generate file key + buf = (Guchar *)gmalloc(72 + fileID->getLength()); +@@ -273,28 +369,52 @@ GBool Decrypt::makeFileKey2(int encVersi + + // test user password + if (encRevision == 2) { ++#ifdef ENABLE_NSS3 ++ rc4Context = rc4InitContext(fileKey, keyLength); ++ if (rc4Context) { ++ for (i = 0; i < 32; ++i) ++ test[i] = rc4DecryptByte(rc4Context, userKey->getChar(i)); ++ PK11_DestroyContext(rc4Context, PR_TRUE); ++ } else { ++ ok = gFalse; ++ } ++#else + rc4InitKey(fileKey, keyLength, fState); + fx = fy = 0; + for (i = 0; i < 32; ++i) { + test[i] = rc4DecryptByte(fState, &fx, &fy, userKey->getChar(i)); + } +- ok = memcmp(test, passwordPad, 32) == 0; ++#endif ++ if (ok) ++ ok = memcmp(test, passwordPad, 32) == 0; + } else if (encRevision == 3) { + memcpy(test, userKey->getCString(), 32); + for (i = 19; i >= 0; --i) { + for (j = 0; j < keyLength; ++j) { + tmpKey[j] = fileKey[j] ^ i; + } ++#ifdef ENABLE_NSS3 ++ rc4Context = rc4InitContext(tmpKey, keyLength); ++ if (rc4Context) { ++ for (j = 0; j < 32; ++j) ++ test[j] = rc4DecryptByte(rc4Context, test[j]); ++ PK11_DestroyContext(rc4Context, PR_TRUE); ++ } else { ++ ok = gFalse; ++ } ++#else + rc4InitKey(tmpKey, keyLength, fState); + fx = fy = 0; + for (j = 0; j < 32; ++j) { + test[j] = rc4DecryptByte(fState, &fx, &fy, test[j]); + } ++#endif + } + memcpy(buf, passwordPad, 32); + memcpy(buf + 32, fileID->getCString(), fileID->getLength()); + md5(buf, 32 + fileID->getLength(), buf); +- ok = memcmp(test, buf, 16) == 0; ++ if (ok) ++ ok = memcmp(test, buf, 16) == 0; + } else { + ok = gFalse; + } +@@ -334,6 +454,9 @@ BaseCryptStream::BaseCryptStream(Stream + if ((objKeyLength = keyLength + 5) > 16) { + objKeyLength = 16; + } ++#ifdef ENABLE_NSS3 ++ state.rc4.context = nullptr; ++#endif + break; + case cryptAES: + objKey[keyLength] = objNum & 0xff; +@@ -349,9 +472,15 @@ BaseCryptStream::BaseCryptStream(Stream + if ((objKeyLength = keyLength + 5) > 16) { + objKeyLength = 16; + } ++#ifdef ENABLE_NSS3 ++ state.aes.context = nullptr; ++#endif + break; + case cryptAES256: + objKeyLength = keyLength; ++#ifdef ENABLE_NSS3 ++ state.aes256.context = nullptr; ++#endif + break; + case cryptNone: + break; +@@ -359,9 +488,32 @@ BaseCryptStream::BaseCryptStream(Stream + + charactersRead = 0; + autoDelete = gTrue; ++ ++#ifdef ENABLE_NSS3 ++ initNSS(); ++#endif + } + + BaseCryptStream::~BaseCryptStream() { ++#ifdef ENABLE_NSS3 ++ switch (algo) { ++ case cryptRC4: ++ if (state.rc4.context) ++ PK11_DestroyContext(state.rc4.context, PR_TRUE); ++ break; ++ case cryptAES: ++ if (state.aes.context) ++ PK11_DestroyContext(state.aes.context, PR_TRUE); ++ break; ++ case cryptAES256: ++ if (state.aes256.context) ++ PK11_DestroyContext(state.aes256.context, PR_TRUE); ++ break; ++ default: ++ break; ++ } ++#endif ++ + if (autoDelete) { + delete str; + } +@@ -424,18 +576,40 @@ void EncryptStream::reset() { + + switch (algo) { + case cryptRC4: ++#ifdef ENABLE_NSS3 ++ if (state.rc4.context) ++ PK11_DestroyContext(state.rc4.context, PR_TRUE); ++ state.rc4.context = rc4InitContext(objKey, objKeyLength); ++#else + state.rc4.x = state.rc4.y = 0; + rc4InitKey(objKey, objKeyLength, state.rc4.state); ++#endif + break; + case cryptAES: ++#ifdef ENABLE_NSS3 ++ memcpy(state.aes.buf, state.aes.cbc, 16); // Copy CBC IV to buf ++ if (state.aes.context) ++ PK11_DestroyContext(state.aes.context, PR_TRUE); ++ state.aes.context = aesInitContext(state.aes.cbc, objKey, objKeyLength, ++ gFalse); ++#else + aesKeyExpansion(&state.aes, objKey, objKeyLength, gFalse); + memcpy(state.aes.buf, state.aes.cbc, 16); // Copy CBC IV to buf ++#endif + state.aes.bufIdx = 0; + state.aes.paddingReached = gFalse; + break; + case cryptAES256: ++#ifdef ENABLE_NSS3 ++ memcpy(state.aes256.buf, state.aes256.cbc, 16); // Copy CBC IV to buf ++ if (state.aes256.context) ++ PK11_DestroyContext(state.aes256.context, PR_TRUE); ++ state.aes256.context = aesInitContext(state.aes256.cbc, objKey, objKeyLength, ++ gFalse); ++#else + aes256KeyExpansion(&state.aes256, objKey, objKeyLength, gFalse); + memcpy(state.aes256.buf, state.aes256.cbc, 16); // Copy CBC IV to buf ++#endif + state.aes256.bufIdx = 0; + state.aes256.paddingReached = gFalse; + break; +@@ -456,7 +630,11 @@ int EncryptStream::lookChar() { + case cryptRC4: + if ((c = str->getChar()) != EOF) { + // RC4 is XOR-based: the decryption algorithm works for encryption too ++#ifdef ENABLE_NSS3 ++ c = rc4DecryptByte(state.rc4.context, (Guchar)c); ++#else + c = rc4DecryptByte(state.rc4.state, &state.rc4.x, &state.rc4.y, (Guchar)c); ++#endif + } + break; + case cryptAES: +@@ -506,21 +684,47 @@ void DecryptStream::reset() { + + switch (algo) { + case cryptRC4: ++#ifdef ENABLE_NSS3 ++ if (state.rc4.context) ++ PK11_DestroyContext(state.rc4.context, PR_TRUE); ++ state.rc4.context = rc4InitContext(objKey, objKeyLength); ++#else + state.rc4.x = state.rc4.y = 0; + rc4InitKey(objKey, objKeyLength, state.rc4.state); ++#endif + break; + case cryptAES: ++#ifdef ENABLE_NSS3 ++ if (state.aes.context) ++ PK11_DestroyContext(state.aes.context, PR_TRUE); ++ for (i = 0; i < 16; ++i) { ++ state.aes.cbc[i] = str->getChar(); ++ } ++ state.aes.context = aesInitContext(state.aes.cbc, objKey, objKeyLength, ++ gTrue); ++#else + aesKeyExpansion(&state.aes, objKey, objKeyLength, gTrue); + for (i = 0; i < 16; ++i) { + state.aes.cbc[i] = str->getChar(); + } ++#endif + state.aes.bufIdx = 16; + break; + case cryptAES256: ++#ifdef ENABLE_NSS3 ++ if (state.aes256.context) ++ PK11_DestroyContext(state.aes256.context, PR_TRUE); ++ for (i = 0; i < 16; ++i) { ++ state.aes256.cbc[i] = str->getChar(); ++ } ++ state.aes256.context = aesInitContext(state.aes256.cbc, objKey, objKeyLength, ++ gTrue); ++#else + aes256KeyExpansion(&state.aes256, objKey, objKeyLength, gTrue); + for (i = 0; i < 16; ++i) { + state.aes256.cbc[i] = str->getChar(); + } ++#endif + state.aes256.bufIdx = 16; + break; + case cryptNone: +@@ -539,10 +743,21 @@ int DecryptStream::lookChar() { + switch (algo) { + case cryptRC4: + if ((c = str->getChar()) != EOF) { ++#ifdef ENABLE_NSS3 ++ if (unlikely(state.rc4.context == nullptr)) ++ c = EOF; ++ else ++ c = rc4DecryptByte(state.rc4.context, (Guchar)c); ++#else + c = rc4DecryptByte(state.rc4.state, &state.rc4.x, &state.rc4.y, (Guchar)c); ++#endif + } + break; + case cryptAES: ++#ifdef ENABLE_NSS3 ++ if (unlikely(state.aes.context == nullptr)) ++ break; ++#endif + if (state.aes.bufIdx == 16) { + if (aesReadBlock(str, in, gFalse)) { + aesDecryptBlock(&state.aes, in, str->lookChar() == EOF); +@@ -555,6 +770,10 @@ int DecryptStream::lookChar() { + } + break; + case cryptAES256: ++#ifdef ENABLE_NSS3 ++ if (unlikely(state.aes256.context == nullptr)) ++ break; ++#endif + if (state.aes256.bufIdx == 16) { + if (aesReadBlock(str, in, gFalse)) { + aes256DecryptBlock(&state.aes256, in, str->lookChar() == EOF); +@@ -576,6 +795,175 @@ int DecryptStream::lookChar() { + // RC4-compatible decryption + //------------------------------------------------------------------------ + ++#ifdef ENABLE_NSS3 ++/* ++ * This function turns given key into token key (compared to a session key ++ * which is prohibited in FIPS mode). ++ */ ++static PK11SymKey *tokenizeKey(const Guchar *key, int keyLen, ++ CK_ATTRIBUTE_TYPE operation) { ++ CK_MECHANISM_TYPE cipherMech = CKM_AES_CBC_PAD; ++ PK11SlotInfo *slot; ++ PK11SymKey *wrappingKey = nullptr; ++ PK11SymKey *symKey = nullptr; ++ PK11SymKey *token = nullptr; ++ SECStatus retval; ++ SECItem *secParam = nullptr; ++ SECItem ivItem, wrappedKey; ++ Guchar output[48]; // Buffer to hold 256 bit key + padding ++ Guchar iv[16]; // Initialization vector for AES ++ Guint outputLength; ++ int i; ++ ++ slot = PK11_GetBestSlot(CKM_AES_KEY_GEN, nullptr); ++ if (slot == nullptr) { ++ error(errInternal, -1, "Unable to find security device (err {0:d})", ++ PR_GetError()); ++ goto err; ++ } ++ ++ // Generate random key for wrapping of given key by AES-256 ++ wrappingKey = PK11_KeyGen(slot, CKM_AES_KEY_GEN, nullptr, 32, nullptr); ++ if (wrappingKey == nullptr) { ++ error(errInternal, -1, "Failed to generate wrapping key (err {0:d})", ++ PR_GetError()); ++ goto err; ++ } ++ ++ for (i = 0; i < 16; i++) ++ iv[i] = i; ++ ++ ivItem.type = siBuffer; ++ ivItem.data = iv; ++ ivItem.len = 16; ++ ++ secParam = PK11_ParamFromIV(cipherMech, &ivItem); ++ if (secParam == nullptr) { ++ error(errInternal, -1, "Failed to set up PKCS11 param (err {0:d})", ++ PR_GetError()); ++ goto err; ++ } ++ ++ // Encrypt given key ++ retval = PK11_Encrypt(wrappingKey, ++ cipherMech, ++ secParam, ++ output, ++ &outputLength, ++ sizeof(output), ++ key, ++ keyLen); ++ if (retval != SECSuccess) { ++ error(errInternal, -1, "Failed to encrypt key (err {0:d})", ++ PR_GetError()); ++ } ++ ++ wrappedKey.type = siBuffer; ++ wrappedKey.data = output; ++ wrappedKey.len = outputLength; ++ ++ // Unwrap the wrapped key to token so it can be used in FIPS mode ++ token = PK11_UnwrapSymKey(wrappingKey, ++ cipherMech, ++ &ivItem, ++ &wrappedKey, ++ operation, ++ CKA_UNWRAP, ++ keyLen); ++ ++ if (token == nullptr) { ++ error(errInternal, -1, "Failed to unwrap symmetric key (err {0:d})", ++ PR_GetError()); ++ } ++ ++err: ++ if (secParam != nullptr) ++ SECITEM_FreeItem(secParam, PR_TRUE); ++ ++ if (wrappingKey != nullptr) ++ PK11_FreeSymKey(wrappingKey); ++ ++ if (symKey != nullptr) ++ PK11_FreeSymKey(symKey); ++ ++ if (slot != nullptr) ++ PK11_FreeSlot(slot); ++ ++ return token; ++} ++ ++static PK11Context *rc4InitContext(const Guchar *key, int keyLen) { ++ CK_MECHANISM_TYPE cipherMech = CKM_RC4; ++ PK11SlotInfo *slot = nullptr; ++ PK11SymKey *symKey = nullptr; ++ SECItem *secParam = nullptr; ++ PK11Context *context = nullptr; ++ ++ slot = PK11_GetBestSlot(cipherMech, nullptr); ++ if (slot == nullptr) { ++ error(errInternal, -1, "Unable to find security device (err {0:d})", ++ PR_GetError()); ++ goto err; ++ } ++ ++ symKey = tokenizeKey(key, keyLen, cipherMech); ++ if (symKey == nullptr) { ++ error(errInternal, -1, "Failed to create token from key (err {0:d})", ++ PR_GetError()); ++ goto err; ++ } ++ ++ secParam = PK11_ParamFromIV(cipherMech, nullptr); ++ if (secParam == nullptr) { ++ error(errInternal, -1, "Failed to set up PKCS11 param (err {0:d})", ++ PR_GetError()); ++ goto err; ++ } ++ ++ context = PK11_CreateContextBySymKey(cipherMech, ++ CKA_DECRYPT, ++ symKey, ++ secParam); ++ if (context == nullptr) { ++ error(errInternal, -1, "Failed to create context (err {0:d})", ++ PR_GetError()); ++ } ++ ++err: ++ if (secParam != nullptr) ++ SECITEM_FreeItem(secParam, PR_TRUE); ++ ++ if (symKey != nullptr) ++ PK11_FreeSymKey(symKey); ++ ++ if (slot != nullptr) ++ PK11_FreeSlot(slot); ++ ++ return context; ++} ++ ++static Guchar rc4DecryptByte(PK11Context *context, Guchar c) { ++ Guchar outputChar = 0; ++ SECStatus retval; ++ int outputLength; ++ ++ retval = PK11_CipherOp(context, ++ &outputChar, ++ &outputLength, ++ 1, ++ &c, ++ 1); ++ ++ if (retval != SECSuccess) { ++ error(errInternal, -1, "Failed to decrypt byte (err {0:d})", ++ PR_GetError()); ++ } ++ ++ return outputChar; ++} ++ ++#else ++ + static void rc4InitKey(Guchar *key, int keyLen, Guchar *state) { + Guchar index1, index2; + Guchar t; +@@ -609,6 +997,8 @@ static Guchar rc4DecryptByte(Guchar *sta + return c ^ state[(tx + ty) % 256]; + } + ++#endif ++ + //------------------------------------------------------------------------ + // AES decryption + //------------------------------------------------------------------------ +@@ -639,6 +1029,178 @@ static GBool aesReadBlock(Stream *str, G + } + } + ++#ifdef ENABLE_NSS3 ++ ++static PK11Context *aesInitContext(Guchar *in, Guchar *objKey, ++ int objKeyLength, GBool decrypt) { ++ CK_MECHANISM_TYPE cipherMech = CKM_AES_CBC; ++ CK_ATTRIBUTE_TYPE operationType = decrypt ? CKA_DECRYPT : CKA_ENCRYPT; ++ PK11SlotInfo *slot; ++ PK11SymKey *symKey = nullptr; ++ SECItem *secParam = nullptr; ++ PK11Context *context = nullptr; ++ SECItem ivItem; ++ ++ slot = PK11_GetBestSlot(cipherMech, nullptr); ++ if (slot == nullptr) { ++ error(errInternal, -1, "Unable to find security device (err {0:d})", ++ PR_GetError()); ++ goto err; ++ } ++ ++ symKey = tokenizeKey(objKey, objKeyLength, cipherMech); ++ if (symKey == nullptr) { ++ error(errInternal, -1, "Failed to create token from key (err {0:d})", ++ PR_GetError()); ++ goto err; ++ } ++ ++ ivItem.type = siBuffer; ++ ivItem.data = in; ++ ivItem.len = 16; ++ ++ secParam = PK11_ParamFromIV(cipherMech, &ivItem); ++ if (secParam == nullptr) { ++ error(errInternal, -1, "Failed to set up PKCS11 param (err {0:d})", ++ PR_GetError()); ++ goto err; ++ } ++ ++ context = PK11_CreateContextBySymKey(cipherMech, ++ operationType, ++ symKey, ++ secParam); ++ ++err: ++ if (secParam != nullptr) ++ SECITEM_FreeItem(secParam, PR_TRUE); ++ ++ if (symKey != nullptr) ++ PK11_FreeSymKey(symKey); ++ ++ if (slot != nullptr) ++ PK11_FreeSlot(slot); ++ ++ return context; ++} ++ ++static void aesEncryptBlock(DecryptAESState *s, Guchar *in) { ++ SECStatus rv; ++ int outputLength; ++ ++ rv = PK11_CipherOp(s->context, ++ s->buf, ++ &outputLength, ++ 16, ++ in, ++ 16); ++ ++ if (rv != SECSuccess) { ++ error(errInternal, -1, "Failed to encrypt input block (err {0:d})", ++ PR_GetError()); ++ goto err; ++ } ++ ++ s->bufIdx = 0; ++ ++err: ++ return; ++} ++ ++static void aesDecryptBlock(DecryptAESState *s, Guchar *in, GBool last) { ++ SECStatus rv1; ++ int outputLen; ++ int n, i; ++ ++ rv1 = PK11_CipherOp(s->context, ++ s->buf, ++ &outputLen, ++ 16, ++ in, ++ 16); ++ ++ if (rv1 != SECSuccess) { ++ error(errInternal, -1, "Failed to decrypt input block (err {0:d})", ++ PR_GetError()); ++ goto err; ++ } ++ ++ s->bufIdx = 0; ++ if (last) { ++ n = s->buf[15]; ++ if (n < 1 || n > 16) { // this should never happen ++ n = 16; ++ } ++ for (i = 15; i >= n; --i) { ++ s->buf[i] = s->buf[i-n]; ++ } ++ s->bufIdx = n; ++ } ++ ++err: ++ return; ++} ++ ++static void aes256EncryptBlock(DecryptAES256State *s, Guchar *in) { ++ SECStatus rv; ++ int outputLength; ++ ++ rv = PK11_CipherOp(s->context, ++ s->buf, ++ &outputLength, ++ 16, ++ in, ++ 16); ++ ++ if (rv != SECSuccess) { ++ error(errInternal, -1, "Failed to encrypt input block (err {0:d})", ++ PR_GetError()); ++ goto err; ++ } ++ ++ s->bufIdx = 0; ++ ++err: ++ return; ++} ++ ++static void aes256DecryptBlock(DecryptAES256State *s, Guchar *in, ++ GBool last) { ++ SECStatus rv1; ++ int outputLen; ++ int n, i; ++ ++ rv1 = PK11_CipherOp(s->context, ++ s->buf, ++ &outputLen, ++ 16, ++ in, ++ 16); ++ ++ if (rv1 != SECSuccess) { ++ error(errInternal, -1, "Failed to decrypt input block (err {0:d})", ++ PR_GetError()); ++ goto err; ++ } ++ ++ s->bufIdx = 0; ++ if (last) { ++ n = s->buf[15]; ++ if (n < 1 || n > 16) { // this should never happen ++ n = 16; ++ } ++ for (i = 15; i >= n; --i) { ++ s->buf[i] = s->buf[i-n]; ++ } ++ s->bufIdx = n; ++ } ++ ++err: ++ return; ++} ++ ++#else ++ + static const Guchar sbox[256] = { + 0x63, 0x7c, 0x77, 0x7b, 0xf2, 0x6b, 0x6f, 0xc5, 0x30, 0x01, 0x67, 0x2b, 0xfe, 0xd7, 0xab, 0x76, + 0xca, 0x82, 0xc9, 0x7d, 0xfa, 0x59, 0x47, 0xf0, 0xad, 0xd4, 0xa2, 0xaf, 0x9c, 0xa4, 0x72, 0xc0, +@@ -1121,10 +1683,33 @@ static void aes256DecryptBlock(DecryptAE + } + } + ++#endif ++ + //------------------------------------------------------------------------ + // MD5 message digest + //------------------------------------------------------------------------ + ++#ifdef ENABLE_NSS3 ++static void hashFunc(const Guchar *msg, int msgLen, Guchar *hash, ++ HASH_HashType type) { ++ HASHContext *context; ++ Guint hashLen = 0; ++ ++ if (!initNSS()) ++ return; ++ ++ context = HASH_Create(type); ++ if (context == nullptr) ++ return; ++ ++ HASH_Begin(context); ++ HASH_Update(context, msg, msgLen); ++ HASH_End(context, hash, &hashLen, HASH_ResultLen(type)); ++ HASH_Destroy(context); ++} ++ ++#else ++ + // this works around a bug in older Sun compilers + static inline Gulong rotateLeft(Gulong x, int r) { + x &= 0xffffffff; +@@ -1151,7 +1736,12 @@ static inline Gulong md5Round4(Gulong a, + return b + rotateLeft((a + (c ^ (b | ~d)) + Xk + Ti), s); + } + ++#endif ++ + void md5(Guchar *msg, int msgLen, Guchar *digest) { ++#ifdef ENABLE_NSS3 ++ hashFunc(msg, msgLen, digest, HASH_AlgMD5); ++#else + Gulong x[16] = {}; + Gulong a, b, c, d, aa, bb, cc, dd; + int n64; +@@ -1296,12 +1886,14 @@ void md5(Guchar *msg, int msgLen, Guchar + digest[13] = (Guchar)((d >>= 8) & 0xff); + digest[14] = (Guchar)((d >>= 8) & 0xff); + digest[15] = (Guchar)((d >>= 8) & 0xff); ++#endif + } + + //------------------------------------------------------------------------ + // SHA-256 hash + //------------------------------------------------------------------------ + ++#ifndef ENABLE_NSS3 + static Guint sha256K[64] = { + 0x428a2f98, 0x71374491, 0xb5c0fbcf, 0xe9b5dba5, + 0x3956c25b, 0x59f111f1, 0x923f82a4, 0xab1c5ed5, +@@ -1400,8 +1992,12 @@ static void sha256HashBlock(Guchar *blk, + H[6] += g; + H[7] += h; + } ++#endif + + static void sha256(Guchar *msg, int msgLen, Guchar *hash) { ++#ifdef ENABLE_NSS3 ++ hashFunc(msg, msgLen, hash, HASH_AlgSHA256); ++#else + Guchar blk[64]; + Guint H[8]; + int blkLen, i; +@@ -1453,7 +2049,10 @@ static void sha256(Guchar *msg, int msgL + hash[i*4 + 2] = (Guchar)(H[i] >> 8); + hash[i*4 + 3] = (Guchar)H[i]; + } ++#endif + } ++ ++#ifndef ENABLE_NSS3 + //------------------------------------------------------------------------ + // SHA-512 hash (see FIPS 180-4) + //------------------------------------------------------------------------ +@@ -1557,8 +2156,12 @@ static void sha512HashBlock(Guchar *blk, + H[6] += g; + H[7] += h; + } ++#endif + + static void sha512(Guchar *msg, int msgLen, Guchar *hash) { ++#ifdef ENABLE_NSS3 ++ hashFunc(msg, msgLen, hash, HASH_AlgSHA512); ++#else + Guchar blk[128]; + uint64_t H[8]; + int blkLen = 0, i; +@@ -1622,6 +2225,7 @@ static void sha512(Guchar *msg, int msgL + hash[i*8 + 6] = (Guchar)(H[i] >> 8); + hash[i*8 + 7] = (Guchar)H[i]; + } ++#endif + } + + //------------------------------------------------------------------------ +@@ -1631,6 +2235,9 @@ static void sha512(Guchar *msg, int msgL + //1.Initial hash value is different. + //2.A 384 bit message digest is obtained by truncating the final hash value. + static void sha384(Guchar *msg, int msgLen, Guchar *hash) { ++#ifdef ENABLE_NSS3 ++ hashFunc(msg, msgLen, hash, HASH_AlgSHA384); ++#else + Guchar blk[128]; + uint64_t H[8]; + int blkLen, i; +@@ -1696,6 +2303,7 @@ static void sha384(Guchar *msg, int msgL + hash[i*8 + 6] = (Guchar)(H[i] >> 8); + hash[i*8 + 7] = (Guchar)H[i]; + } ++#endif + } + + //------------------------------------------------------------------------ +@@ -1725,7 +2333,8 @@ static void revision6Hash(GooString *inp + //a.make the string K1 + memcpy(K1, inputPassword, inputPasswordLength); + memcpy(K1 + inputPasswordLength, K , KLength); +- memcpy(K1 + inputPasswordLength + KLength, userKey, userKeyLength); ++ if (userKey) ++ memcpy(K1 + inputPasswordLength + KLength, userKey, userKeyLength); + for(int i = 1; i < 64 ; ++i) { + memcpy(K1 + (i * sequenceLength),K1,sequenceLength); + } +@@ -1735,7 +2344,11 @@ static void revision6Hash(GooString *inp + memcpy(state.buf, state.cbc, 16); // Copy CBC IV to buf + state.bufIdx = 0; + state.paddingReached = gFalse; ++#ifdef ENABLE_NSS3 ++ state.context = aesInitContext(state.cbc, aesKey, 16, gFalse); ++#else + aesKeyExpansion(&state,aesKey,16,gFalse); ++#endif + + for(int i = 0; i < (4 * sequenceLength); i++) { + aesEncryptBlock(&state,K1 + (16 * i)); +@@ -1776,6 +2389,9 @@ static void revision6Hash(GooString *inp + sha512(E, totalLength, K); + } + rounds++; ++#ifdef ENABLE_NSS3 ++ PK11_DestroyContext(state.context, PR_TRUE); ++#endif + } + // the first 32 bytes of the final K are the output of the function. + } +diff --git a/poppler/Decrypt.h b/poppler/Decrypt.h +index d4667c8c..16fa9830 100644 +--- a/poppler/Decrypt.h ++++ b/poppler/Decrypt.h +@@ -31,6 +32,9 @@ + #include "goo/GooString.h" + #include "Object.h" + #include "Stream.h" ++#ifdef ENABLE_NSS3 ++#include ++#endif + + //------------------------------------------------------------------------ + // Decrypt +@@ -73,13 +77,21 @@ private: + * previous output is kept in buf. The paddingReached field is only used in + * case of encryption. */ + struct DecryptRC4State { ++#ifdef ENABLE_NSS3 ++ PK11Context *context; ++#else + Guchar state[256]; + Guchar x, y; ++#endif + }; + + struct DecryptAESState { ++#ifdef ENABLE_NSS3 ++ PK11Context *context; ++#else + Guint w[44]; + Guchar state[16]; ++#endif + Guchar cbc[16]; + Guchar buf[16]; + GBool paddingReached; // encryption only +@@ -87,8 +99,12 @@ struct DecryptAESState { + }; + + struct DecryptAES256State { ++#ifdef ENABLE_NSS3 ++ PK11Context *context; ++#else + Guint w[60]; + Guchar state[16]; ++#endif + Guchar cbc[16]; + Guchar buf[16]; + GBool paddingReached; // encryption only +diff --git a/poppler/poppler-config.h.cmake b/poppler/poppler-config.h.cmake +index f0a5a1a0..dcaade6f 100644 +--- a/poppler/poppler-config.h.cmake ++++ b/poppler/poppler-config.h.cmake +@@ -115,6 +115,12 @@ + #cmakedefine USE_CMS 1 + #endif + ++/* Build against libnss3 for digital signature validation and ++ implementation of encryption/decryption. */ ++#ifndef ENABLE_NSS3 ++#cmakedefine ENABLE_NSS3 1 ++#endif ++ + // Also, there are preprocessor symbols in the header files + // that are used but never defined when building poppler using configure + // or cmake: DISABLE_OUTLINE, DEBUG_MEM, +--- poppler-0.66.0/CMakeLists.txt ++++ poppler-0.66.0/CMakeLists.txt +@@ -490,7 +490,7 @@ add_library(poppler STATIC ${poppler_SRC + else() + add_library(poppler ${poppler_SRCS}) + endif() +-set_target_properties(poppler PROPERTIES VERSION 77.0.0 SOVERSION 77) ++set_target_properties(poppler PROPERTIES VERSION 78.0.0 SOVERSION 78) + if(MINGW) + get_target_property(POPPLER_SOVERSION poppler SOVERSION) + set_target_properties(poppler PROPERTIES SUFFIX "-${POPPLER_SOVERSION}${CMAKE_SHARED_LIBRARY_SUFFIX}") diff --git a/SPECS/poppler.spec b/SPECS/poppler.spec index b34d750..d2cf10d 100644 --- a/SPECS/poppler.spec +++ b/SPECS/poppler.spec @@ -4,7 +4,7 @@ Summary: PDF rendering library Name: poppler Version: 0.66.0 -Release: 11%{?dist}.12 +Release: 26%{?dist} License: (GPLv2 or GPLv3) and GPLv2+ and LGPLv2+ and MIT URL: http://poppler.freedesktop.org/ Source0: http://poppler.freedesktop.org/poppler-%{version}.tar.xz @@ -42,23 +42,23 @@ Patch9: poppler-0.66.0-valid-embedded-file-name.patch # https://bugzilla.redhat.com/show_bug.cgi?id=1644094 Patch10: poppler-0.66.0-tiling-patterns.patch -# https://bugzilla.redhat.com/show_bug.cgi?id=1665259 -Patch11: poppler-0.66.0-rich-media-annotation.patch - -# https://bugzilla.redhat.com/show_bug.cgi?id=1665273 -Patch12: poppler-0.66.0-check-catalog-is-dict.patch - # https://bugzilla.redhat.com/show_bug.cgi?id=1646546 -Patch13: poppler-0.66.0-display-profile.patch +Patch11: poppler-0.66.0-display-profile.patch # https://bugzilla.redhat.com/show_bug.cgi?id=1665266 -Patch14: poppler-0.66.0-dummy-xref-entry.patch +Patch12: poppler-0.66.0-dummy-xref-entry.patch # https://bugzilla.redhat.com/show_bug.cgi?id=1672419 -Patch15: poppler-0.66.0-negative-xref-indices.patch +Patch13: poppler-0.66.0-negative-xref-indices.patch + +# https://bugzilla.redhat.com/show_bug.cgi?id=1665259 +Patch14: poppler-0.66.0-rich-media-annotation.patch # https://bugzilla.redhat.com/show_bug.cgi?id=1665263 -Patch16: poppler-0.66.0-filespec.patch +Patch15: poppler-0.66.0-filespec.patch + +# https://bugzilla.redhat.com/show_bug.cgi?id=1665273 +Patch16: poppler-0.66.0-check-catalog-is-dict.patch # https://bugzilla.redhat.com/show_bug.cgi?id=1683632 Patch17: poppler-0.66.0-image-stream-getline.patch @@ -70,15 +70,18 @@ Patch19: poppler-0.66.0-rescale-filter.patch # https://bugzilla.redhat.com/show_bug.cgi?id=1691724 Patch20: poppler-0.66.0-stack-overflow.patch -# https://bugzilla.redhat.com/show_bug.cgi?id=1713582 -Patch21: poppler-0.66.0-jpeg2000-component-size.patch +# https://bugzilla.redhat.com/show_bug.cgi?id=1618766 +Patch21: poppler-0.66.0-nss.patch -# https://bugzilla.redhat.com/show_bug.cgi?id=1696636 -Patch22: poppler-0.66.0-PSOutputDev-rgb.patch +# https://bugzilla.redhat.com/show_bug.cgi?id=1713582 +Patch22: poppler-0.66.0-jpeg2000-component-size.patch # https://bugzilla.redhat.com/show_bug.cgi?id=1732340 Patch23: poppler-0.66.0-JPXStream-length.patch +# https://bugzilla.redhat.com/show_bug.cgi?id=1696636 +Patch24: poppler-0.66.0-PSOutputDev-rgb.patch + BuildRequires: cmake BuildRequires: gettext-devel BuildRequires: pkgconfig(cairo) @@ -196,6 +199,7 @@ export CC="gcc -fPIC" # hack to make the cmake call pass -DENABLE_LIBOPENJPEG=openjpeg2 \ -DENABLE_XPDF_HEADERS=ON \ -DENABLE_ZLIB=OFF \ + -DENABLE_NSS=ON \ .. unset CC make %{?_smp_mflags} @@ -231,7 +235,7 @@ test "$(pkg-config --modversion poppler-splash)" = "%{version}" %files %doc README %license COPYING -%{_libdir}/libpoppler.so.77* +%{_libdir}/libpoppler.so.78* %files devel %{_libdir}/pkgconfig/poppler.pc @@ -280,57 +284,69 @@ test "$(pkg-config --modversion poppler-splash)" = "%{version}" %{_mandir}/man1/* %changelog -* Wed Aug 14 2019 Marek Kasik - 0.66.0-11.el8_0.12 -- Ignore dict Length if it is broken -- Resolves: #1741146 +* Tue Aug 13 2019 Marek Kasik - 0.66.0-26 +- Coverity scan related fixes +- Related: #1618766 -* Wed Aug 14 2019 Marek Kasik - 0.66.0-11.el8_0.11 +* Tue Aug 13 2019 Marek Kasik - 0.66.0-25 - Check whether input is RGB in PSOutputDev::checkPageSlice() -- (also when using "-optimizecolorspace" flag) -- Resolves: #1741145 +- also when using "-optimizecolorspace" flag +- Resolves: #1697576 -* Wed Aug 14 2019 Marek Kasik - 0.66.0-11.el8_0.10 +* Fri Aug 9 2019 Marek Kasik - 0.66.0-24 +- Check whether input is RGB in PSOutputDev::checkPageSlice() +- Resolves: #1697576 + +* Fri Aug 9 2019 Marek Kasik - 0.66.0-23 +- Ignore dict Length if it is broken +- Resolves: #1733027 + +* Fri Aug 9 2019 Marek Kasik - 0.66.0-22 - Fail gracefully if not all components of JPEG2000Stream - have the same size -- Resolves: #1740612 +- Resolves: #1723505 -* Wed Jul 31 2019 Marek Kasik - 0.66.0-11.el8_0.9 +* Fri Jun 28 2019 Marek Kasik - 0.66.0-21 +- Implement crypto functions using NSS +- Resolves: #1618766 + +* Wed Apr 3 2019 Marek Kasik - 0.66.0-20 - Fix stack overflow on broken file -- Resolves: #1717867 +- Resolves: #1691887 -* Wed Jul 31 2019 Marek Kasik - 0.66.0-11.el8_0.8 +* Mon Apr 1 2019 Marek Kasik - 0.66.0-19 - Constrain number of cycles in rescale filter - Compute correct coverage values for box filter -- Resolves: #1717866 +- Resolves: #1688418 -* Wed Jul 31 2019 Marek Kasik - 0.66.0-11.el8_0.7 +* Mon Apr 1 2019 Marek Kasik - 0.66.0-18 - Fix possible crash on broken files in ImageStream::getLine() -- Resolves: #1717803 +- Resolves: #1685268 + +* Mon Apr 1 2019 Marek Kasik - 0.66.0-17 +- Check Catalog from XRef for being a Dict +- Resolves: #1677347 -* Wed Jul 31 2019 Marek Kasik - 0.66.0-11.el8_0.6 +* Mon Apr 1 2019 Marek Kasik - 0.66.0-16 - Move the fileSpec.dictLookup call inside fileSpec.isDict if -- Resolves: #1717788 +- Resolves: #1677028 -* Wed Jul 31 2019 Marek Kasik - 0.66.0-11.el8_0.5 +* Mon Apr 1 2019 Marek Kasik - 0.66.0-15 +- Do not try to construct invalid rich media annotation assets +- Resolves: #1677025 + +* Mon Apr 1 2019 Marek Kasik - 0.66.0-14 - Defend against requests for negative XRef indices -- Resolves: #1717779 +- Resolves: #1673699 -* Wed Jul 31 2019 Marek Kasik - 0.66.0-11.el8_0.4 +* Mon Apr 1 2019 Marek Kasik - 0.66.0-13 - Do not try to parse into unallocated XRef entry -- Resolves: #1717790 +- Resolves: #1677057 -* Wed Jul 31 2019 Marek Kasik - 0.66.0-11.el8_0.3 +* Mon Apr 1 2019 Marek Kasik - 0.66.0-12 - Avoid global display profile state becoming an uncontrolled - memory leak -- Resolves: #1717776 - -* Wed May 15 2019 Marek Kasik - 0.66.0-11.el8_0.2 -- Check Catalog from XRef for being a Dict -- Resolves: #1690480 - -* Wed May 15 2019 Marek Kasik - 0.66.0-11.el8_0.1 -- Do not try to construct invalid rich media annotation assets -- Resolves: #1690478 +- Resolves: #1646552 * Fri Dec 14 2018 Marek Kasik - 0.66.0-11 - Fix tiling patterns when pattern cell is too far