WebKit Bugzilla
Attachment 348128 Details for
Bug 188978
: [WinCairo] Add CryptoDigestOpenSSL
Home
|
New
|
Browse
|
Search
|
[?]
|
Reports
|
Requests
|
Help
|
New Account
|
Log In
Remember
[x]
|
Forgot Password
Login:
[x]
[patch]
patch
bug188978-1.patch (text/plain), 17.67 KB, created by
Yoshiaki Jitsukawa
on 2018-08-27 02:29:37 PDT
(
hide
)
Description:
patch
Filename:
MIME Type:
Creator:
Yoshiaki Jitsukawa
Created:
2018-08-27 02:29:37 PDT
Size:
17.67 KB
patch
obsolete
>diff --git a/Source/WebCore/PAL/ChangeLog b/Source/WebCore/PAL/ChangeLog >index a9c4bbc5e73..f4801a9409d 100644 >--- a/Source/WebCore/PAL/ChangeLog >+++ b/Source/WebCore/PAL/ChangeLog >@@ -1,3 +1,28 @@ >+2018-08-27 Yoshiaki Jitsukawa <yoshiaki.jitsukawa@sony.com> >+ >+ [WinCairo] Add CryptoDigiestOpenSSL >+ https://bugs.webkit.org/show_bug.cgi?id=188978 >+ >+ Reviewed by NOBODY (OOPS!). >+ >+ Add a CryptoDigest implementation with OpenSSL/LibreSSL and let the >+ WinCairo port use it. >+ >+ * pal/PlatformAppleWin.cmake: Add CryptoDigestWin.cpp to PAL_SOURCES >+ * pal/PlatformWin.cmake: Remove CryptoDigestWin.cpp from PAL_SOURCES >+ * pal/PlatformWinCairo.cmake: Add CryptoDigestOpenSSL to PAL_SOURCES >+ * pal/crypto/openssl/CryptoDigestOpenSSL.cpp: Added. >+ (PAL::toSHA1Context): >+ (PAL::toSHA224Context): >+ (PAL::toSHA256Context): >+ (PAL::toSHA384Context): >+ (PAL::toSHA512Context): >+ (PAL::CryptoDigest::CryptoDigest): >+ (PAL::CryptoDigest::~CryptoDigest): >+ (PAL::CryptoDigest::create): >+ (PAL::CryptoDigest::addBytes): >+ (PAL::CryptoDigest::computeHash): >+ > 2018-08-26 Andy Estes <aestes@apple.com> > > [Apple Pay] Introduce new values for -apple-pay-button-type >diff --git a/Source/WebCore/PAL/pal/PlatformAppleWin.cmake b/Source/WebCore/PAL/pal/PlatformAppleWin.cmake >index 3521652acc6..a1d2da24dd7 100644 >--- a/Source/WebCore/PAL/pal/PlatformAppleWin.cmake >+++ b/Source/WebCore/PAL/pal/PlatformAppleWin.cmake >@@ -29,6 +29,8 @@ list(APPEND PAL_SOURCES > avfoundation/MediaTimeAVFoundation.cpp > > cf/CoreMediaSoftLink.cpp >+ >+ crypto/win/CryptoDigestWin.cpp > ) > > list(APPEND PAL_PRIVATE_INCLUDE_DIRECTORIES >diff --git a/Source/WebCore/PAL/pal/PlatformWin.cmake b/Source/WebCore/PAL/pal/PlatformWin.cmake >index cbcbcb93978..8108c2091c2 100644 >--- a/Source/WebCore/PAL/pal/PlatformWin.cmake >+++ b/Source/WebCore/PAL/pal/PlatformWin.cmake >@@ -1,6 +1,4 @@ > list(APPEND PAL_SOURCES >- crypto/win/CryptoDigestWin.cpp >- > system/ClockGeneric.cpp > > system/win/SoundWin.cpp >diff --git a/Source/WebCore/PAL/pal/PlatformWinCairo.cmake b/Source/WebCore/PAL/pal/PlatformWinCairo.cmake >index d82629a66d4..e88d07612c0 100644 >--- a/Source/WebCore/PAL/pal/PlatformWinCairo.cmake >+++ b/Source/WebCore/PAL/pal/PlatformWinCairo.cmake >@@ -1,2 +1,6 @@ > list(APPEND PAL_PUBLIC_HEADERS > ) >+ >+list(APPEND PAL_SOURCES >+ crypto/openssl/CryptoDigestOpenSSL.cpp >+) >diff --git a/Source/WebCore/PAL/pal/crypto/openssl/CryptoDigestOpenSSL.cpp b/Source/WebCore/PAL/pal/crypto/openssl/CryptoDigestOpenSSL.cpp >new file mode 100644 >index 00000000000..4028dae1f63 >--- /dev/null >+++ b/Source/WebCore/PAL/pal/crypto/openssl/CryptoDigestOpenSSL.cpp >@@ -0,0 +1,210 @@ >+/* >+ * Copyright (C) 2018 Sony Interactive Entertainment Inc. >+ * >+ * Redistribution and use in source and binary forms, with or without >+ * modification, are permitted provided that the following conditions >+ * are met: >+ * 1. Redistributions of source code must retain the above copyright >+ * notice, this list of conditions and the following disclaimer. >+ * 2. Redistributions in binary form must reproduce the above copyright >+ * notice, this list of conditions and the following disclaimer in the >+ * documentation and/or other materials provided with the distribution. >+ * >+ * THIS SOFTWARE IS PROVIDED BY APPLE INC. AND ITS CONTRIBUTORS ``AS IS'' >+ * AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, >+ * THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR >+ * PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL APPLE INC. OR ITS CONTRIBUTORS >+ * BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR >+ * CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF >+ * SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS >+ * INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN >+ * CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) >+ * ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF >+ * THE POSSIBILITY OF SUCH DAMAGE. >+ */ >+ >+#include "config.h" >+#include "CryptoDigest.h" >+ >+#include <openssl/sha.h> >+ >+namespace PAL { >+ >+struct CryptoDigestContext { >+ CryptoDigest::Algorithm algorithm; >+ void* shaContext; >+}; >+ >+#ifndef OPENSSL_NO_SHA1 >+inline SHA_CTX* toSHA1Context(CryptoDigestContext* context) >+{ >+ ASSERT(context->algorithm == CryptoDigest::Algorithm::SHA_1); >+ return static_cast<SHA_CTX*>(context->shaContext); >+} >+#endif >+#ifndef OPENSSL_NO_SHA256 >+inline SHA256_CTX* toSHA224Context(CryptoDigestContext* context) >+{ >+ ASSERT(context->algorithm == CryptoDigest::Algorithm::SHA_224); >+ return static_cast<SHA256_CTX*>(context->shaContext); >+} >+inline SHA256_CTX* toSHA256Context(CryptoDigestContext* context) >+{ >+ ASSERT(context->algorithm == CryptoDigest::Algorithm::SHA_256); >+ return static_cast<SHA256_CTX*>(context->shaContext); >+} >+#endif >+#ifndef OPENSSL_NO_SHA512 >+inline SHA512_CTX* toSHA384Context(CryptoDigestContext* context) >+{ >+ ASSERT(context->algorithm == CryptoDigest::Algorithm::SHA_384); >+ return static_cast<SHA512_CTX*>(context->shaContext); >+} >+inline SHA512_CTX* toSHA512Context(CryptoDigestContext* context) >+{ >+ ASSERT(context->algorithm == CryptoDigest::Algorithm::SHA_512); >+ return static_cast<SHA512_CTX*>(context->shaContext); >+} >+#endif >+ >+CryptoDigest::CryptoDigest() >+ : m_context(new CryptoDigestContext) >+{ >+} >+ >+CryptoDigest::~CryptoDigest() >+{ >+ switch (m_context->algorithm) { >+#ifndef OPENSSL_NO_SHA1 >+ case CryptoDigest::Algorithm::SHA_1: >+ delete toSHA1Context(m_context.get()); >+ return; >+#endif >+#ifndef OPENSSL_NO_SHA256 >+ case CryptoDigest::Algorithm::SHA_224: >+ delete toSHA224Context(m_context.get()); >+ return; >+ case CryptoDigest::Algorithm::SHA_256: >+ delete toSHA256Context(m_context.get()); >+ return; >+#endif >+#ifndef OPENSSL_NO_SHA512 >+ case CryptoDigest::Algorithm::SHA_384: >+ delete toSHA384Context(m_context.get()); >+ return; >+ case CryptoDigest::Algorithm::SHA_512: >+ delete toSHA512Context(m_context.get()); >+ return; >+#endif >+ } >+} >+ >+std::unique_ptr<CryptoDigest> CryptoDigest::create(CryptoDigest::Algorithm algorithm) >+{ >+ std::unique_ptr<CryptoDigest> digest(new CryptoDigest); >+ digest->m_context->algorithm = algorithm; >+ >+ switch (algorithm) { >+#ifndef OPENSSL_NO_SHA1 >+ case CryptoDigest::Algorithm::SHA_1: { >+ SHA_CTX* context = new SHA_CTX; >+ digest->m_context->shaContext = context; >+ SHA1_Init(context); >+ return digest; >+ } >+#endif >+#ifndef OPENSSL_NO_SHA256 >+ case CryptoDigest::Algorithm::SHA_224: { >+ SHA256_CTX* context = new SHA256_CTX; >+ digest->m_context->shaContext = context; >+ SHA224_Init(context); >+ return digest; >+ } >+ case CryptoDigest::Algorithm::SHA_256: { >+ SHA256_CTX* context = new SHA256_CTX; >+ digest->m_context->shaContext = context; >+ SHA256_Init(context); >+ return digest; >+ } >+#endif >+#ifndef OPENSSL_NO_SHA512 >+ case CryptoDigest::Algorithm::SHA_384: { >+ SHA512_CTX* context = new SHA512_CTX; >+ digest->m_context->shaContext = context; >+ SHA384_Init(context); >+ return digest; >+ } >+ case CryptoDigest::Algorithm::SHA_512: { >+ SHA512_CTX* context = new SHA512_CTX; >+ digest->m_context->shaContext = context; >+ SHA512_Init(context); >+ return digest; >+ } >+#endif >+ } >+ >+ return nullptr; >+} >+ >+void CryptoDigest::addBytes(const void* input, size_t length) >+{ >+ switch (m_context->algorithm) { >+#ifndef OPENSSL_NO_SHA1 >+ case CryptoDigest::Algorithm::SHA_1: >+ SHA1_Update(toSHA1Context(m_context.get()), input, length); >+ return; >+#endif >+#ifndef OPENSSL_NO_SHA256 >+ case CryptoDigest::Algorithm::SHA_224: >+ SHA224_Update(toSHA224Context(m_context.get()), input, length); >+ return; >+ case CryptoDigest::Algorithm::SHA_256: >+ SHA256_Update(toSHA256Context(m_context.get()), input, length); >+ return; >+#endif >+#ifndef OPENSSL_NO_SHA512 >+ case CryptoDigest::Algorithm::SHA_384: >+ SHA384_Update(toSHA384Context(m_context.get()), input, length); >+ return; >+ case CryptoDigest::Algorithm::SHA_512: >+ SHA512_Update(toSHA512Context(m_context.get()), input, length); >+ return; >+ } >+#endif >+} >+ >+Vector<uint8_t> CryptoDigest::computeHash() >+{ >+ Vector<uint8_t> result; >+ switch (m_context->algorithm) { >+#ifndef OPENSSL_NO_SHA1 >+ case CryptoDigest::Algorithm::SHA_1: >+ result.resize(SHA_DIGEST_LENGTH); >+ SHA1_Final(result.data(), toSHA1Context(m_context.get())); >+ break; >+#endif >+#ifndef OPENSSL_NO_SHA256 >+ case CryptoDigest::Algorithm::SHA_224: >+ result.resize(SHA224_DIGEST_LENGTH); >+ SHA224_Final(result.data(), toSHA224Context(m_context.get())); >+ break; >+ case CryptoDigest::Algorithm::SHA_256: >+ result.resize(SHA256_DIGEST_LENGTH); >+ SHA256_Final(result.data(), toSHA256Context(m_context.get())); >+ break; >+#endif >+#ifndef OPENSSL_NO_SHA512 >+ case CryptoDigest::Algorithm::SHA_384: >+ result.resize(SHA384_DIGEST_LENGTH); >+ SHA384_Final(result.data(), toSHA384Context(m_context.get())); >+ break; >+ case CryptoDigest::Algorithm::SHA_512: >+ result.resize(SHA512_DIGEST_LENGTH); >+ SHA512_Final(result.data(), toSHA512Context(m_context.get())); >+ break; >+ } >+#endif >+ return result; >+} >+ >+} // namespace PAL >diff --git a/Tools/ChangeLog b/Tools/ChangeLog >index 63a875cc580..2bdffc94df0 100644 >--- a/Tools/ChangeLog >+++ b/Tools/ChangeLog >@@ -1,3 +1,30 @@ >+2018-08-27 Yoshiaki Jitsukawa <yoshiaki.jitsukawa@sony.com> >+ >+ [WinCairo] Add CryptoDigiestOpenSSL >+ https://bugs.webkit.org/show_bug.cgi?id=188978 >+ >+ Reviewed by NOBODY (OOPS!). >+ >+ Add API tests for the PAL::CryptoDigest class. >+ >+ * TestWebKitAPI/PlatformWin.cmake: >+ Add CryptoDigest.cpp to TestWebCoreLib_Sources. >+ >+ Define -DSTATICALLY_LINKED_WITH_PAL=1 to avoid warnings since >+ without the definition the functions marked with PAL_EXPORT are supposed to be >+ imported from another shared library, but as it is, TestWebCoreLib >+ links PAL statically. >+ >+ * TestWebKitAPI/Tests/WebCore/CryptoDigest.cpp: Added. >+ (TestWebKitAPI::toHex): >+ (TestWebKitAPI::expect): >+ (TestWebKitAPI::expectSHA1): >+ (TestWebKitAPI::expectSHA224): >+ (TestWebKitAPI::expectSHA256): >+ (TestWebKitAPI::expectSHA384): >+ (TestWebKitAPI::expectSHA512): >+ (TestWebKitAPI::TEST): >+ > 2018-08-26 Sam Weinig <sam@webkit.org> > > Using _WKRemoteObjectInterface with a protocol that inherits from a non-NSObject protocol crashes >diff --git a/Tools/TestWebKitAPI/PlatformWin.cmake b/Tools/TestWebKitAPI/PlatformWin.cmake >index fc6309eed1c..ec591eeaa04 100644 >--- a/Tools/TestWebKitAPI/PlatformWin.cmake >+++ b/Tools/TestWebKitAPI/PlatformWin.cmake >@@ -75,6 +75,7 @@ if (${WTF_PLATFORM_WIN_CAIRO}) > ) > list(APPEND TestWebCoreLib_SOURCES > ${TESTWEBKITAPI_DIR}/Tests/WebCore/win/BitmapImage.cpp >+ ${TESTWEBKITAPI_DIR}/Tests/WebCore/CryptoDigest.cpp > ) > else () > list(APPEND test_webcore_LIBRARIES >@@ -125,6 +126,10 @@ target_link_libraries(TestWebCoreLib ${test_webcore_LIBRARIES}) > set_target_properties(TestWebCoreLib PROPERTIES OUTPUT_NAME "TestWebCoreLib") > add_dependencies(TestWebCoreLib ${forwarding_headers_dependencies}) > >+if (PAL_LIBRARY_TYPE MATCHES STATIC) >+ target_compile_definitions(TestWebCoreLib PRIVATE -DSTATICALLY_LINKED_WITH_PAL=1) >+endif () >+ > add_executable(TestWebCore > ${TOOLS_DIR}/win/DLLLauncher/DLLLauncherMain.cpp > ) >diff --git a/Tools/TestWebKitAPI/Tests/WebCore/CryptoDigest.cpp b/Tools/TestWebKitAPI/Tests/WebCore/CryptoDigest.cpp >new file mode 100644 >index 00000000000..e6cc5742a85 >--- /dev/null >+++ b/Tools/TestWebKitAPI/Tests/WebCore/CryptoDigest.cpp >@@ -0,0 +1,127 @@ >+/* >+ * Copyright (C) 2018 Sony Interactive Entertainment Inc. >+ * >+ * Redistribution and use in source and binary forms, with or without >+ * modification, are permitted provided that the following conditions >+ * are met: >+ * 1. Redistributions of source code must retain the above copyright >+ * notice, this list of conditions and the following disclaimer. >+ * 2. Redistributions in binary form must reproduce the above copyright >+ * notice, this list of conditions and the following disclaimer in the >+ * documentation and/or other materials provided with the distribution. >+ * >+ * THIS SOFTWARE IS PROVIDED BY APPLE INC. AND ITS CONTRIBUTORS ``AS IS'' >+ * AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, >+ * THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR >+ * PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL APPLE INC. OR ITS CONTRIBUTORS >+ * BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR >+ * CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF >+ * SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS >+ * INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN >+ * CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) >+ * ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF >+ * THE POSSIBILITY OF SUCH DAMAGE. >+ */ >+ >+#include "config.h" >+ >+#include <PAL/crypto/CryptoDigest.h> >+#include <wtf/text/CString.h> >+ >+namespace TestWebKitAPI { >+ >+static CString toHex(WTF::Vector<uint8_t>&& hash) >+{ >+ const char hex[] = "0123456789ABCDEF"; >+ >+ WTF::Vector<char> buffer(hash.size() * 2); >+ for (size_t i = 0; i < hash.size(); i++) { >+ uint8_t hi = hash[i] >> 4; >+ uint8_t lo = hash[i] & 0x0F; >+ buffer[2 * i] = hex[hi]; >+ buffer[2 * i + 1] = hex[lo]; >+ } >+ >+ return CString(buffer.data(), buffer.size()); >+} >+ >+static void expect(PAL::CryptoDigest::Algorithm algorithm, const CString& input, int repeat, const CString& expected) >+{ >+ auto cryptoDigest = PAL::CryptoDigest::create(algorithm); >+ >+ for (int i = 0; i < repeat; ++i) >+ cryptoDigest->addBytes(input.data(), input.length()); >+ >+ CString actual = toHex(cryptoDigest->computeHash()); >+ >+ ASSERT_EQ(expected.length(), actual.length()); >+ ASSERT_STREQ(expected.data(), actual.data()); >+} >+ >+static void expectSHA1(const CString& input, int repeat, const CString& expected) >+{ >+ expect(PAL::CryptoDigest::Algorithm::SHA_1, input, repeat, expected); >+} >+ >+static void expectSHA224(const CString& input, int repeat, const CString& expected) >+{ >+ expect(PAL::CryptoDigest::Algorithm::SHA_224, input, repeat, expected); >+} >+ >+static void expectSHA256(const CString& input, int repeat, const CString& expected) >+{ >+ expect(PAL::CryptoDigest::Algorithm::SHA_256, input, repeat, expected); >+} >+ >+static void expectSHA384(const CString& input, int repeat, const CString& expected) >+{ >+ expect(PAL::CryptoDigest::Algorithm::SHA_384, input, repeat, expected); >+} >+ >+static void expectSHA512(const CString& input, int repeat, const CString& expected) >+{ >+ expect(PAL::CryptoDigest::Algorithm::SHA_512, input, repeat, expected); >+} >+ >+TEST(CryptoDigest, SHA1Computation) >+{ >+ // Examples taken from sample code in RFC 3174. >+ expectSHA1("abc", 1, "A9993E364706816ABA3E25717850C26C9CD0D89D"); >+ expectSHA1("abcdbcdecdefdefgefghfghighijhijkijkljklmklmnlmnomnopnopq", 1, "84983E441C3BD26EBAAE4AA1F95129E5E54670F1"); >+ expectSHA1("a", 1000000, "34AA973CD4C4DAA4F61EEB2BDBAD27316534016F"); >+ expectSHA1("0123456701234567012345670123456701234567012345670123456701234567", 10, "DEA356A2CDDD90C7A7ECEDC5EBB563934F460452"); >+} >+ >+TEST(CryptoDigest, SHA224Computation) >+{ >+ // Examples taken from sample code in RFC 3874. >+ expectSHA224("abc", 1, "23097D223405D8228642A477BDA255B32AADBCE4BDA0B3F7E36C9DA7"); >+ expectSHA224("abcdbcdecdefdefgefghfghighijhijkijkljklmklmnlmnomnopnopq", 1, "75388B16512776CC5DBA5DA1FD890150B0C6455CB4F58B1952522525"); >+ expectSHA224("a", 1000000, "20794655980C91D8BBB4C1EA97618A4BF03F42581948B2EE4EE7AD67"); >+} >+ >+TEST(CryptoDigest, SHA256Computation) >+{ >+ // Examples taken from sample code in FIPS-180. >+ expectSHA256("abc", 1, "BA7816BF8F01CFEA414140DE5DAE2223B00361A396177A9CB410FF61F20015AD"); >+ expectSHA256("abcdbcdecdefdefgefghfghighijhijkijkljklmklmnlmnomnopnopq", 1, "248D6A61D20638B8E5C026930C3E6039A33CE45964FF2167F6ECEDD419DB06C1"); >+ expectSHA256("a", 1000000, "CDC76E5C9914FB9281A1C7E284D73E67F1809A48A497200E046D39CCC7112CD0"); >+} >+ >+TEST(CryptoDigest, SHA384Computation) >+{ >+ // Examples taken from sample code in FIPS-180. >+ expectSHA384("abc", 1, "CB00753F45A35E8BB5A03D699AC65007272C32AB0EDED1631A8B605A43FF5BED8086072BA1E7CC2358BAECA134C825A7"); >+ expectSHA384("abcdefghbcdefghicdefghijdefghijkefghijklfghijklmghijklmnhijklmnoijklmnopjklmnopqklmnopqrlmnopqrsmnopqrstnopqrstu", 1, "09330C33F71147E83D192FC782CD1B4753111B173B3B05D22FA08086E3B0F712FCC7C71A557E2DB966C3E9FA91746039"); >+ expectSHA384("a", 1000000, "9D0E1809716474CB086E834E310A4A1CED149E9C00F248527972CEC5704C2A5B07B8B3DC38ECC4EBAE97DDD87F3D8985"); >+} >+ >+TEST(CryptoDigest, SHA512Computation) >+{ >+ // Examples taken from sample code in FIPS-180. >+ expectSHA512("abc", 1, "DDAF35A193617ABACC417349AE20413112E6FA4E89A97EA20A9EEEE64B55D39A2192992A274FC1A836BA3C23A3FEEBBD454D4423643CE80E2A9AC94FA54CA49F"); >+ expectSHA512("abcdefghbcdefghicdefghijdefghijkefghijklfghijklmghijklmnhijklmnoijklmnopjklmnopqklmnopqrlmnopqrsmnopqrstnopqrstu", 1, "8E959B75DAE313DA8CF4F72814FC143F8F7779C6EB9F7FA17299AEADB6889018501D289E4900F7E4331B99DEC4B5433AC7D329EEB6DD26545E96E55B874BE909"); >+ expectSHA512("a", 1000000, "E718483D0CE769644E2E42C7BC15B4638E1F98B13B2044285632A803AFA973EBDE0FF244877EA60A4CB0432CE577C31BEB009C5C2C49AA2E4EADB217AD8CC09B"); >+} >+ >+}
You cannot view the attachment while viewing its details because your browser does not support IFRAMEs.
View the attachment on a separate page
.
View Attachment As Diff
View Attachment As Raw
Actions:
View
|
Formatted Diff
|
Diff
Attachments on
bug 188978
:
348128
|
348235
|
348399