ninja-labs-tech / verify-pdf Goto Github PK
View Code? Open in Web Editor NEWVerify pdf signatures in JS
Verify pdf signatures in JS
I'm using Browserify and trying to verify the signature in the browser.
Using fileReader I create an arraybuffer and then in the browerified node package
convert to a buffer before passing it to verifyPDF().
Using a valid signed pdf I get the following error: 'Unknown message digest digestAlgorithm'
I've extracted the digestAlgorithm at verifyPDF.js:
`�H\u0001e\u0003\u0004\u0002\u0001
I think this is an encoding problem.
The signature:
0�\u0006H\u0006\t�H�÷\r\u0001\u0007\u0002 �\u000690�\u00065\u0002\u0001\u00011\u000f0\r\u0006\t�H\u0001e\u0003\u0004\u0002\u0001\u0005\u00000\u000b\u0006\t*�H�÷\r\u0001\u0007\u0001 �\u0003ä0�\u0003à0�\u0002È \u0003\u0002\u0001\u0002\u0002\t\u0000¥\nÌS(·
Æ0\r\u0006\t�H�÷\r\u0001\u0001\u000b\u0005\u00000��1\u000b0\t\u0006\u0003U\u0004\u0006\u0013\u0002BG1\u00130\u0011\u0006\u0003U\u0004\b\f\nSome-State1\u00120\u0010\u0006\u0003U\u0004\u0007\f\tSome City1\u00150\u0013\u0006\u0003U\u0004\n\f\fSome Company1\u00100\u000e\u0006\u0003U\u0004\u0003\f\u0007signpdf1"0 \u0006\t�H�÷\r\u0001\t\u0001\u0016\[email protected] \u0017\r180808134020Z\u0018\u000f22920522134020Z0��1\u000b0\t\u0006\u0003U\u0004\u0006\u0013\u0002BG1\u00130\u0011\u0006\u0003U\u0004\b\f\nSome-State1\u00120\u0010\u0006\u0003U\u0004\u0007\f\tSome City1\u00150\u0013\u0006\u0003U\u0004\n\f\fSome Company1\u00100\u000e\u0006\u0003U\u0004\u0003\f\u0007signpdf1"0 \u0006\t�H�÷\r\u0001\t\u0001\u0016\[email protected]�\u0001"0\r\u0006\t�H�÷\r\u0001\u0001\u0001\u0005\u0000\u0003�\u0001\u000f\u00000�\u0001\n\u0002�\u0001\u0001\u0000Ì;¸¹weé�CÖD�§a¾O�z,\u00034Õõ\u0005ô�Írl\u001d´Y8f/ôݬÒMGèãÉJïá¿�\r\u001eE\u0010î^}£ãæg~ÇþÙÖV\u0000ÿû(ï.2x?�§\t{Àû�Êp\u0015�1D�®KG�aI�×\u000eFPJY¦\f\u0003i¸\u0012¾à¸=y}û]V4�ÿ\u0002N7��ÝÇ|ÎíL# J¥JüfH\u001cÎV"\u0016ó\u001cûf��a%<<¯»ï4{&\f\u001a¬áÅ%\u0002��d»÷\u0018X\u0000Ât \u0001(F\u0018zì\f+×ø�f´E�)iõÂØÔ\u0006¿÷�ÿ°\u0011ÑyÍ.<¹Â�\u0013iO@8äP<jsX�×À��Þ\u001eðµò³ç³\b\u001düQô\n={äTò�=�·_\u0002\u0003\u0001\u0000\u0001£S0Q0\u001d\u0006\u0003U\u001d\u000e\u0004\u0016\u0004\u0014K�kw�\u0013¿ÿeû&�àÓ>d\u0010üÊ�0\u001f\u0006\u0003U\u001d#\u0004\u00180\u0016�\u0014K�kw�\u0013¿ÿeû&�àÓ>d\u0010üÊ�0\u000f\u0006\u0003U\u001d\u0013\u0001\u0001ÿ\u0004\u00050\u0003\u0001\u0001ÿ0\r\u0006\t*�H�÷\r\u0001\u0001\u000b\u0005\u0000\u0003�\u0001\u0001\u0000\u0003\rÿ\u0018þG�\u0006(#�ýå\tä¹F�!d¯i�â½ôƧÇ{>Hì\u0011x\u0019Îá��¶�ÀRá#\u0010Ï>?A\u0013¨�«Mù«��5ó)\u000f% \u0004íh\u0015\u00165}ûæøe\u0006)�ù\u0014°\b}]�5_K�ù\u0001^õfæ\r9ߪ$�
±CX\u0010ë�1fÎÆ�'\"Òø�Û¿&.�hv´�¾\u000b\u0019dá�\u0003hH�U�3\fvË=�ë�fS\u0018²f]ðxAâÆ_?I�\u001d�¢ÂÙæ\t¾ËJ\t�@\u0014é�à0¥#÷þ��÷3\u0019Ù§Áú��P\u0005\u0014�T\fþ{xÑ8qô\u0019åe�o�4À9Å��:±iBñ�«Ç\u0004^Åc\b3§©\u0016ͬ�7jK\u000b\u0014¤\n�n7.Á1�\u0002(0�\u0002$\u0002\u0001\u00010��0��1\u000b0\t\u0006\u0003U\u0004\u0006\u0013\u0002BG1\u00130\u0011\u0006\u0003U\u0004\b\f\nSome-State1\u00120\u0010\u0006\u0003U\u0004\u0007\f\tSome City1\u00150\u0013\u0006\u0003U\u0004\n\f\fSome Company1\u00100\u000e\u0006\u0003U\u0004\u0003\f\u0007signpdf1\"0 \u0006\t*�H�÷\r\u0001\t\u0001\u0016\[email protected]\u0002\t\u0000¥\nÌS(·
Æ0\r\u0006\t�H\u0001e\u0003\u0004\u0002\u0001\u0005\u0000 i0\u0018\u0006\t*�H�÷\r\u0001\t\u00031\u000b\u0006\t*�H�÷\r\u0001\u0007\u00010/\u0006\t*�H�÷\r\u0001\t\u00041\"\u0004 RɺÈú±�Íyû\t\u0007bU½jßÿïNu¼y}ðiìÈ�\u0012\u0001\u00020\u001c\u0006\t*�H�÷\r\u0001\t\u00051\u000f\u0017\r191105181350Z0\r\u0006\t*�H�÷\r\u0001\u0001\u0001\u0005\u0000\u0004�\u0001\u0000d,§¦ZUH\u00011vâNÛ_»k\\,3\u0010\b\u000fnê»w\u0000\u001bzõ=xü�á\u000536\u000b,ÂD\u0004éþ�Û�KKD %*À¾\u0018nmÃöÞ[E}ÓÞÐ\u0001\u001czAwåoX\u001c�\u0018\u001cº\\ç�§D�\u0015Ï[\f-�mÃÐ�\u0017�·q´²«£Ì�h��ä\u0015âÁ©�øËb\u001dàø�4 \u001cþ@\n�öÅRw\u000eF]®Û\u0010¼Ýö�Ô3z�0�é���§r\u0000�{ª\u0014©Ø¸FòH#
i�W�tkÞoô!¡"æj²(¤¥Û'+ÀDØÇ�¶Ë·�¯kðG2ÁgA×nÛ\�Ô��ð�\u001b'\u0014��¦\u0010Æs�ü�|*Ã�G\u0004\u001b�®}ð|4\u001eU¥¶\u0002âó �c\u0014ìð\u0000\u0000\u0000\u0000\u0000\u0000\u0000\u0000\u0000\u0000\u0000\u0000\u0000\u0000\u0000\u0000\u0000\u0000\u0000\u0000\u0000\u0000\u0000\u0000\u0000\u0000\u0000\u0000\u0000\u0000\u0000\u0000\u0000\u0000\u0000\u0000\u0000\u0000\u0000\u0000\u0000\u0000\u0000\u0000\u0000\u0000\u0000\u0000\u0000\u0000\u0000\u0000\u0000\u0000\u0000\u0000\u0000\u0000\u0000\u0000\u0000\u0000\u0000\u0000\u0000\u0000\u0000\u0000\u0000\u0000\u0000\u0000\u0000\u0000\u0000\u0000\u0000\u0000\u0000\u0000\u0000\u0000\u0000\u0000\u0000\u0000\u0000\u0000\u0000\u0000\u0000\u0000\u0000\u0000\u0000\u0000\u0000\u0000\u0000\u0000\u0000\u0000\u0000\u0000\u0000\u0000\u0000\u0000\u0000\u0000\u0000\u0000\u0000\u0000\u0000\u0000\u0000\u0000\u0000\u0000\u0000\u0000\u0000\u0000\u0000\u0000\u0000\u0000\u0000\u0000\u0000\u0000\u0000\u0000\u0000\u0000\u0000\u0000\u0000\u0000\u0000\u0000\u0000\u0000\u0000\u0000\u0000\u0000\u0000\u0000\u0000\u0000\u0000\u0000\u0000\u0000\u0000\u0000\u0000\u0000\u0000\u0000\u0000\u0000\u0000\u0000\u0000\u0000\u0000\u0000\u0000\u0000\u0000\u0000\u0000\u0000\u0000\u0000\u0000\u0000\u0000\u0000\u0000\u0000\u0000\u0000\u0000\u0000\u0000\u0000\u0000\u0000\u0000\u0000\u0000\u0000\u0000\u0000\u0000\u0000\u0000\u0000\u0000\u0000\u0000\u0000\u0000\u0000\u0000\u0000\u0000\u0000\u0000\u0000\u0000\u0000\u0000\u0000\u0000\u0000\u0000\u0000\u0000\u0000\u0000\u0000\u0000\u0000\u0000\u0000\u0000\u0000\u0000\u0000\u0000\u0000\u0000\u0000\u0000\u0000\u0000\u0000\u0000\u0000\u0000\u0000\u0000\u0000\u0000\u0000\u0000\u0000\u0000\u0000\u0000\u0000\u0000\u0000\u0000\u0000\u0000\u0000\u0000\u0000\u0000\u0000\u0000\u0000\u0000\u0000\u0000\u0000\u0000\u0000\u0000\u0000\u0000\u0000\u0000\u0000\u0000\u0000\u0000\u0000\u0000\u0000\u0000\u0000\u0000\u0000\u0000\u0000\u0000\u0000\u0000\u0000\u0000\u0000\u0000\u0000\u0000\u0000\u0000\u0000\u0000\u0000\u0000\u0000\u0000\u0000\u0000\u0000\u0000\u0000\u0000\u0000\u0000\u0000\u0000\u0000\u0000\u0000\u0000\u0000\u0000\u0000\u0000\u0000\u0000\u0000\u0000\u0000\u0000\u0000\u0000\u0000\u0000\u0000\u0000\u0000\u0000\u0000\u0000\u0000\u0000\u0000\u0000\u0000\u0000\u0000\u0000\u0000\u0000\u0000\u0000\u0000\u0000\u0000\u0000\u0000\u0000\u0000\u0000\u0000\u0000\u0000\u0000\u0000\u0000\u0000\u0000\u0000\u0000\u0000\u0000\u0000\u0000\u0000\u0000\u0000\u0000\u0000\u0000\u0000\u0000\u0000\u0000\u0000\u0000\u0000\u0000\u0000\u0000\u0000\u0000\u0000\u0000\u0000\u0000\u0000\u0000\u0000\u0000\u0000\u0000\u0000\u0000\u0000\u0000\u0000\u0000\u0000\u0000\u0000\u0000\u0000\u0000\u0000\u0000\u0000\u0000\u0000\u0000\u0000\u0000\u0000\u0000\u0000\u0000\u0000\u0000\u0000\u0000\u0000\u0000\u0000\u0000\u0000\u0000\u0000\u0000\u0000\u0000\u0000\u0000\u0000\u0000\u0000\u0000\u0000\u0000\u0000\u0000\u0000\u0000\u0000\u0000\u0000\u0000\u0000\u0000\u0000\u0000\u0000\u0000\u0000\u0000\u0000\u0000\u0000\u0000\u0000\u0000\u0000\u0000\u0000\u0000\u0000\u0000\u0000\u0000\u0000\u0000\u0000\u0000\u0000\u0000\u0000\u0000\u0000\u0000\u0000\u0000\u0000\u0000\u0000\u0000\u0000\u0000\u0000\u0000\u0000\u0000\u0000\u0000\u0000\u0000\u0000\u0000\u0000\u0000\u0000\u0000\u0000\u0000\u0000\u0000\u0000\u0000\u0000\u0000\u0000\u0000\u0000\u0000\u0000\u0000\u0000\u0000\u0000\u0000\u0000\u0000\u0000\u0000\u0000\u0000\u0000\u0000\u0000\u0000\u0000\u0000\u0000\u0000\u0000\u0000\u0000\u0000\u0000\u0000\u0000\u0000\u0000\u0000\u0000\u0000\u0000\u0000\u0000\u0000\u0000\u0000\u0000\u0000\u0000\u0000\u0000\u0000\u0000\u0000\u0000\u0000\u0000\u0000\u0000\u0000\u0000\u0000\u0000\u0000\u0000\u0000\u0000\u0000\u0000\u0000\u0000\u0000\u0000\u0000\u0000\u0000\u0000\u0000\u0000\u0000\u0000\u0000\u0000\u0000\u0000\u0000\u0000\u0000\u0000\u0000\u0000\u0000\u0000\u0000\u0000\u0000\u0000\u0000\u0000\u0000\u0000\u0000\u0000\u0000\u0000\u0000\u0000\u0000\u0000\u0000\u0000\u0000\u0000\u0000\u0000\u0000\u0000\u0000\u0000\u0000\u0000\u0000\u0000\u0000\u0000\u0000\u0000\u0000\u0000\u0000\u0000\u0000\u0000\u0000\u0000\u0000\u0000\u0000\u0000\u0000\u0000\u0000\u0000\u0000\u0000\u0000\u0000\u0000\u0000\u0000\u0000\u0000\u0000\u0000\u0000\u0000\u0000\u0000\u0000\u0000\u0000\u0000\u0000\u0000\u0000\u0000\u0000\u0000\u0000\u0000\u0000\u0000\u0000\u0000\u0000\u0000\u0000\u0000\u0000\u0000\u0000\u0000\u0000\u0000\u0000\u0000\u0000\u0000\u0000\u0000\u0000\u0000\u0000\u0000\u0000\u0000\u0000\u0000\u0000\u0000\u0000\u0000\u0000\u0000\u0000\u0000\u0000\u0000\u0000\u0000\u0000\u0000\u0000\u0000\u0000\u0000\u0000\u0000\u0000\u0000\u0000\u0000\u0000\u0000\u0000\u0000\u0000\u0000\u0000\u0000\u0000\u0000\u0000\u0000\u0000\u0000\u0000\u0000\u0000\u0000\u0000\u0000\u0000\u0000\u0000\u0000\u0000\u0000\u0000\u0000\u0000\u0000\u0000\u0000\u0000\u0000\u0000\u0000\u0000\u0000\u0000\u0000\u0000\u0000\u0000\u0000\u0000\u0000\u0000\u0000\u0000\u0000\u0000\u0000\u0000\u0000\u0000\u0000\u0000\u0000\u0000\u0000\u0000\u0000\u0000\u0000\u0000\u0000\u0000\u0000\u0000\u0000\u0000\u0000\u0000\u0000\u0000\u0000\u0000\u0000\u0000\u0000\u0000\u0000\u0000\u0000\u0000\u0000\u0000\u0000\u0000\u0000\u0000\u0000\u0000\u0000\u0000\u0000\u0000\u0000\u0000\u0000\u0000\u0000\u0000\u0000\u0000\u0000\u0000\u0000\u0000\u0000\u0000\u0000\u0000\u0000\u0000\u0000\u0000\u0000\u0000\u0000\u0000\u0000\u0000\u0000\u0000\u0000\u0000\u0000\u0000\u0000\u0000\u0000\u0000\u0000\u0000\u0000\u0000\u0000\u0000\u0000\u0000\u0000\u0000\u0000\u0000\u0000\u0000\u0000\u0000\u0000\u0000\u0000\u0000\u0000\u0000\u0000\u0000\u0000\u0000\u0000\u0000\u0000\u0000\u0000\u0000\u0000\u0000\u0000\u0000\u0000\u0000\u0000\u0000\u0000\u0000\u0000\u0000\u0000\u0000\u0000\u0000\u0000\u0000\u0000\u0000\u0000\u0000\u0000\u0000\u0000\u0000\u0000\u0000\u0000\u0000\u0000\u0000\u0000\u0000\u0000\u0000\u0000\u0000\u0000\u0000\u0000\u0000\u0000\u0000\u0000\u0000\u0000\u0000\u0000\u0000\u0000\u0000\u0000\u0000\u0000\u0000\u0000\u0000\u0000\u0000\u0000\u0000\u0000\u0000\u0000\u0000\u0000\u0000\u0000\u0000\u0000\u0000\u0000\u0000\u0000\u0000\u0000\u0000\u0000\u0000\u0000
I have a valid document, that after processing with verify-pdf it returns authenticity
: false
.
Looking at the code, I see the that the root cause is that the authenticateSignature()
function in verification.js calls verifyCaBundle()
that will only return true if there are multiple certificates in the signed PDF (at least 2), and the chain is valid, meaning each certificate is the the issuer of the next:
const verifyCaBundle = (certs) => !!certs
.find((cert, i) => certs[i + 1] && certs[i + 1].issued(cert));
The PDF I've used (of a brazilian digital ID), the PDF is signed using only one certificate and not a chain, so the verifyCaBundle
function returns false, and the authenticity is false.
Is it a must for a PDF to have a certificate chain?
I noticed that when "forging" signed PDFs with Illustrator, the program is smart and does not touch the signed byte range—it rather appends a copy of the whole file to itself and modifies the new byte range (doubling the file size), all while maintaining a completely valid signature.
I gave this some thought and at least for my use case (preventing unauthorized modification of PDF files), I will check the size of the PDF against the upper bound of the byte range:
// helpers/extractSignature.js
if (ByteRange[2] + ByteRange[3] < pdfBuffer.length) {
throw new VerifyPDFError(
'Failed PDF size verification.',
VerifyPDFError.TYPE_INPUT,
);
}
I am by no means an expert in PDF signing and I'm not aware of the implications of this behavior, so please tell me if this doesn't make sense. Otherwise, I'd be happy to create a PR for this issue.
In any case, thanks for this library, it taught me a lot of things about PDF signing!
Hi. How can I run this module in the browser?
Can I, without Nodjs, directly connect this module on the client side (browser)?
Example from readme does not work =
Or maybe there is an alternative for getting information about the signature in the pdf file in the js in the browser?
Hey @MohammedEssehemy ! I tried to use verify-pdf but when I ran it over a pdf with two signatures I get this output:
console.log src/signpdf.test.js:162
{ verified: false,
authenticity: false,
integrity: true,
expired: false,
meta:
{ certs: [ [Object] ],
signatureMeta:
{ reason: 'first',
contactInfo: '[email protected]',
location: 'Location from p12' } } }
It doesn't seem to recognize the second signature.
If I run mutools I get this output:
➜ node-signpdf git:(develop) ✗ mutool sign -v resources/signed-twice.pdf
verifying signature 18
Designated name: CN=signpdf, O=Some Company, OU=, [email protected], C=BG
Certificate error: Self-signed certificate.
The signature is valid but there have been edits since signing.
verifying signature 21
Designated name: CN=SignPdf, O=node-signpdf, OU=, [email protected], C=BG
Certificate error: Self-signed certificate.
The document is unchanged since signing.
The file is this:
signed-twice.pdf
_Originally posted by @andres-blanco in vbuch/node-signpdf#38 (comment)
Following readme I tried to add library to my project:
const verifyPDF = require('@ninja-labs/verify-pdf');
...
const {
verified,
authenticity,
integrity,
expired,
meta
} = verifyPDF(signedPdfBuffer);
but it throws an error
ERROR in /Users/sebastianWebstormProjects/pdf-project/node_modules/@ninja-labs/verify-pdf/lib/helpers/verification.js
Module not found: Error: Can't resolve './rootCAs' in '/Users/sebastianWebstormProjects/WebstormProjects/pdf-project/node_modules/@ninja-labs/verify-pdf/lib/helpers'
ERROR in /Users/sebastianWebstormProjects/WebstormProjects/pdf-project/node_modules/@ninja-labs/verify-pdf/lib/helpers/verification.js
Module not found: Error: Can't resolve 'tls' in '/Users/sebastianWebstormProjects/WebstormProjects/pdf-project/node_modules/@ninja-labs/verify-pdf/lib/helpers'
Hi, I basically need to verify the date on which the document was signed.
The current implementation validates the expire date of the certificate, but I need to know if the PDF was signed during a valid period. (I will also get the certificate revocation status later by ocsp protocol).
I can use authenticity && integrity
instead of the current authenticity && integrity && !expired
, but I need to get the sign date.
Can it be done? Thanks in advance.
Since node-signpdf now updated their node-forge dependency to 1.2.1 it is incompatible with this module that uses 0.10.0. Updating it directly, expectedly, breaks the code. Meaning it doesn't detect signatures anymore but also doesn't throw out errors.
npm ERR! code 1
npm ERR! path [userpath]/node_modules/@ninja-labs/verify-pdf
npm ERR! command failed
npm ERR! command sh -c npm i ./packages/buffer --no-save
npm ERR! npm ERR! code ERESOLVE
npm ERR! npm ERR! ERESOLVE unable to resolve dependency tree
npm ERR! npm ERR!
npm ERR! npm ERR! While resolving: @ninja-labs/[email protected]
npm ERR! npm ERR! Found: [email protected]
npm ERR! npm ERR! node_modules/node-forge
npm ERR! npm ERR! node-forge@"^0.10.0" from the root project
npm ERR! npm ERR!
npm ERR! npm ERR! Could not resolve dependency:
npm ERR! npm ERR! peer node-forge@"^1.2.1" from [email protected]
npm ERR! npm ERR! node_modules/node-signpdf
npm ERR! npm ERR! dev node-signpdf@"^1.0.2" from the root project
npm ERR! npm ERR!
npm ERR! npm ERR! Fix the upstream dependency conflict, or retry
npm ERR! npm ERR! this command with --force, or --legacy-peer-deps
npm ERR! npm ERR! to accept an incorrect (and potentially broken) dependency resolution.
npm ERR! npm ERR!
npm ERR! npm ERR! See [userpath]/.npm/eresolve-report.txt for a full report.
npm ERR!
npm ERR! npm ERR! A complete log of this run can be found in:
npm ERR! npm ERR! [userpath]/.npm/_logs/2022-04-11T13_43_11_002Z-debug-0.log
npm ERR! A complete log of this run can be found in:
npm ERR! [userpath]/.npm/_logs/2022-04-11T13_41_31_071Z-debug-0.log
On running the npm i command for ninja labs it prompts a npm error and aborts the installation.
b-trust.pdf
The attached file is signed with an invisible signature.
The signature is verified by Adobe acrobat DC and the root cert is extracted correctly.
When using your package though, the root cert is not extracted, only the client cert.,
I investigated the code and noticed that the problem is in lib/helpers/general.js getMessageFromSignature method which returns only the client certificate.
Can you check?
Thanks in advance.
const verifyPDF = require("@ninja-labs/verify-pdf");
const { verified, authenticity, integrity, expired, signatures } = verifyPDF(buffer);
{
verified: false,
authenticity: undefined,
integrity: undefined,
expired: undefined,
signatures: undefined
}
The PDF, when opened with LibreOffice or Adobe Acrobat, is shown to have "valid signature".
After digging in, the PDF was signed using algorithm: "sha256withrsaencryption". I'm unable to find much info about it. Is it something the lib could handle in the future?
I am trying to use your library to validate a vaccine receipt issued by Ontario, Canada. The cert info looks ok, but the verify method call failed with Encryption block is invalid. I can email you the test file.
Any hints for me?
thx, Billy.
certs = [ { "clientCertificate": true, "issuedBy": { "countryName": "US", "organizationName": "Entrust, Inc.", "organizationalUnitName": "(c) 2014 Entrust, Inc. - for authorized use only", "commonName": "Entrust Certification Authority - L1M" }, "issuedTo": { "countryName": "CA", "stateOrProvinceName": "Ontario", "localityName": "Toronto", "jurisdictionOfIncorporationCountryName": "CA", "jurisdictionOfIncorporationStateOrProvinceName": "Ontario", "organizationName": "Ontario Health", "businessCategory": "Government Entity", "serialName": "18-04-2019", "commonName": "covid19signer.ontariohealth.ca" }, "validityPeriod": { "notBefore": "2021-05-20T13:41:50.000Z", "notAfter": "2022-06-19T13:41:49.000Z" }, "pemCertificate": "-----BEGIN CERTIFICATE-----\r\nMIIHNTCCBh2gAwIBAgIQanhJa+fBXT8GQ8QG/t9p4TANBgkqhkiG9w0BAQsFADCB\r\nujELMAkGA1UEBhMCVVMxFjAUBgNVBAoTDUVudHJ1c3QsIEluYy4xKDAmBgNVBAsT\r\nH1NlZSB3d3cuZW50cnVzdC5uZXQvbGVnYWwtdGVybXMxOTA3BgNVBAsTMChjKSAy\r\nMDE0IEVudHJ1c3QsIEluYy4gLSBmb3IgYXV0aG9yaXplZCB1c2Ugb25seTEuMCwG\r\nA1UEAxMlRW50cnVzdCBDZXJ0aWZpY2F0aW9uIEF1dGhvcml0eSAtIEwxTTAeFw0y\r\nMTA1MjAxMzQxNTBaFw0yMjA2MTkxMzQxNDlaMIHTMQswCQYDVQQGEwJDQTEQMA4G\r\nA1UECBMHT250YXJpbzEQMA4GA1UEBxMHVG9yb250bzETMBEGCysGAQQBgjc8AgED\r\nEwJDQTEYMBYGCysGAQQBgjc8AgECEwdPbnRhcmlvMRcwFQYDVQQKEw5PbnRhcmlv\r\nIEhlYWx0aDEaMBgGA1UEDxMRR292ZXJubWVudCBFbnRpdHkxEzARBgNVBAUTCjE4\r\nLTA0LTIwMTkxJzAlBgNVBAMTHmNvdmlkMTlzaWduZXIub250YXJpb2hlYWx0aC5j\r\nYTCCASIwDQYJKoZIhvcNAQEBBQADggEPADCCAQoCggEBAL2bD+Ng1RNYCNVVtEQ3\r\nzg8JKFvRWFFPIF/UTXGg3iArK1tKr1xtjx6OdFtwosHyo+3ksPRicc4KeuV6/QMF\r\nqiVJ5IOy9TSVImJsmONgFyEiak0dGYG5SeHiWwyaUvkniWd7U3wWEl4nOZuLAYu4\r\n8ZLot8p8Q/UaNvAoNsRDv6YDGjL2yGHaXxi3Bb6XTQTLcevuEQeM6g1LtKyisZfB\r\nQ8TKThBq99EojwHfXIhddxbPKLeXvWJgK1TcL17UFIwx6ig74s0LyYqEPm8Oa8qR\r\n+IesFUT9Liv7xhV+tU52wmNfDi4znmLvs5Cmh/vmcHKyhEbxhYqciWJocACth5ij\r\nE3kCAwEAAaOCAxowggMWMAwGA1UdEwEB/wQCMAAwHQYDVR0OBBYEFFoW3zt+jaHS\r\npm1EV5hU4XD+mwO5MB8GA1UdIwQYMBaAFMP30LUqMK2vDZEhcDlU3byJcMc6MGgG\r\nCCsGAQUFBwEBBFwwWjAjBggrBgEFBQcwAYYXaHR0cDovL29jc3AuZW50cnVzdC5u\r\nZXQwMwYIKwYBBQUHMAKGJ2h0dHA6Ly9haWEuZW50cnVzdC5uZXQvbDFtLWNoYWlu\r\nMjU2LmNlcjAzBgNVHR8ELDAqMCigJqAkhiJodHRwOi8vY3JsLmVudHJ1c3QubmV0\r\nL2xldmVsMW0uY3JsMCkGA1UdEQQiMCCCHmNvdmlkMTlzaWduZXIub250YXJpb2hl\r\nYWx0aC5jYTAOBgNVHQ8BAf8EBAMCBaAwHQYDVR0lBBYwFAYIKwYBBQUHAwEGCCsG\r\nAQUFBwMCMEsGA1UdIAREMEIwNwYKYIZIAYb6bAoBAjApMCcGCCsGAQUFBwIBFhto\r\ndHRwczovL3d3dy5lbnRydXN0Lm5ldC9ycGEwBwYFZ4EMAQEwggF+BgorBgEEAdZ5\r\nAgQCBIIBbgSCAWoBaAB3AFYUBpov18Ls0/XhvUSyPsdGdrm8mRFcwO+UmFXWidDd\r\nAAABeYoCz+MAAAQDAEgwRgIhAKGKAoZMzwkh/3sZXq6vtEYhoYHfZzsjh9jqZvfS\r\nxQVZAiEAmJu/ftbkNFBr8751Z9wA2dpI0Qt+LoeL1TJQ833Kdg4AdQDfpV6raIJP\r\nH2yt7rhfTj5a6s2iEqRqXo47EsAgRFwqcwAAAXmKAs/cAAAEAwBGMEQCICsD/Vj+\r\nypZeHhesMyv/TkS5ftQjqyIaAFTL/02Gtem4AiBcWdPQspH3vfzZr4LO9z4u5jTg\r\nPsfm5PZr66tI7yASrAB2AEalVet1+pEgMLWiiWn0830RLEF0vv1JuIWr8vxw/m1H\r\nAAABeYoC0WkAAAQDAEcwRQIgTL5F11+7KhQ60jnODm9AkyvXRLY32Mj6tgudRAXO\r\ny7UCIQDd/dU+Ax1y15yiAA5xM+bWJ7T+Ztd99SD1lw/o8fEmOjANBgkqhkiG9w0B\r\nAQsFAAOCAQEAlpV3RoNvnhDgd2iFSF39wytf1R6/0u5FdL7eIkYNfnkqXu9Ux9cO\r\n/OeaGAFMSzaDPA8Xt9A0HqkEbh1pr7UmZVqBwDr4a7gczvt7+HFJRn//Q2fwhmaw\r\nvXTLLxcAPQF00G6ySsc9MUbsArh6AVhMf9tSXgNaTDj3X3UyYDfR+G8H9eVG/LPp\r\n34QV/8uvPUFXGj6MjdQysx6YG+K3mae0GEVpODEl4MiceEFZ7v4CPA6pFNadijRF\r\n6tdXky2psuo7VXfnE2WIlahKr56x+8R6To5pcWglKTywTqvCbnKRRVZhXXYo3Awd\r\n8h9+TbL3ACHDqA4fi5sAbZ7nMXp8RK4o5A==\r\n-----END CERTIFICATE-----\r\n" }, { "issuedBy": { "countryName": "US", "organizationName": "Entrust, Inc.", "organizationalUnitName": "(c) 2009 Entrust, Inc. - for authorized use only", "commonName": "Entrust Root Certification Authority - G2" }, "issuedTo": { "countryName": "US", "organizationName": "Entrust, Inc.", "organizationalUnitName": "(c) 2009 Entrust, Inc. - for authorized use only", "commonName": "Entrust Root Certification Authority - G2" }, "validityPeriod": { "notBefore": "2009-07-07T17:25:54.000Z", "notAfter": "2030-12-07T17:55:54.000Z" }, "pemCertificate": "-----BEGIN CERTIFICATE-----\r\nMIIEPjCCAyagAwIBAgIESlOMKDANBgkqhkiG9w0BAQsFADCBvjELMAkGA1UEBhMC\r\nVVMxFjAUBgNVBAoTDUVudHJ1c3QsIEluYy4xKDAmBgNVBAsTH1NlZSB3d3cuZW50\r\ncnVzdC5uZXQvbGVnYWwtdGVybXMxOTA3BgNVBAsTMChjKSAyMDA5IEVudHJ1c3Qs\r\nIEluYy4gLSBmb3IgYXV0aG9yaXplZCB1c2Ugb25seTEyMDAGA1UEAxMpRW50cnVz\r\ndCBSb290IENlcnRpZmljYXRpb24gQXV0aG9yaXR5IC0gRzIwHhcNMDkwNzA3MTcy\r\nNTU0WhcNMzAxMjA3MTc1NTU0WjCBvjELMAkGA1UEBhMCVVMxFjAUBgNVBAoTDUVu\r\ndHJ1c3QsIEluYy4xKDAmBgNVBAsTH1NlZSB3d3cuZW50cnVzdC5uZXQvbGVnYWwt\r\ndGVybXMxOTA3BgNVBAsTMChjKSAyMDA5IEVudHJ1c3QsIEluYy4gLSBmb3IgYXV0\r\naG9yaXplZCB1c2Ugb25seTEyMDAGA1UEAxMpRW50cnVzdCBSb290IENlcnRpZmlj\r\nYXRpb24gQXV0aG9yaXR5IC0gRzIwggEiMA0GCSqGSIb3DQEBAQUAA4IBDwAwggEK\r\nAoIBAQC6hLZy254Ma+KZ6TABp3bqMriVQRrJ2mFOWHLP/vaCeb9zYQYKpSfYs1/T\r\nRU4cctZOMvJyig/3gxnQaoCAAEUesMfnmr8SVycco2gvCoe9amsOXmXzHHfV1IWN\r\ncCG0szLni6LVhjkCsbjSR87kyUnEO6fe+1R9V77w6G7CebI6C1XiUJgWMhNcL3hW\r\nwcKUs/Ja5CeanyTXxuzQmyWC48zCxEXFjJd6BmsqEZ+pCm5IO2/b1BEZQvePB7/1\r\nU1+cPvQXLOZprE4yTGJ36rfo5bs0vBmLrpxR57d+tVOxMyLlbc9wPBr64ptntoP0\r\njaWvYkxN4FisZDQSA/i2jZRjJKRxAgMBAAGjQjBAMA4GA1UdDwEB/wQEAwIBBjAP\r\nBgNVHRMBAf8EBTADAQH/MB0GA1UdDgQWBBRqciZ60B7vfec7aVHUbI2fkBJmqzAN\r\nBgkqhkiG9w0BAQsFAAOCAQEAeZ8dlsa2eT8ijYfThwMEYGprmi5ZiXMRrEPR9RP/\r\njTkrwPK9T3CMqS/qF8QLVJ7UG5aYMzyorWKiAHarWWluBh1+xLlEjZivEtRh2woZ\r\nRkfz6/djwUAFQKXSt/S1mja/qYh2iARVBCuch38aNzx+LaUa2NSJXsq9rD1s2G2v\r\n1fN2D807iDginWyTmsQ9v4IbZT+mD12q/OWyFcq1rca8PdCE6OoGcrBNOTJ4vz4R\r\nnAuknZoh8/CbCzB428Hch0P+vGOaysXCHMnHjf87ElgI5rY97HosTvuDls4MPGmH\r\nVHOkc8KT/1EQrBVUAdj8BbGJoX90g5pJ19xOe4pIb4tF9g==\r\n-----END CERTIFICATE-----\r\n" } ]
A declarative, efficient, and flexible JavaScript library for building user interfaces.
🖖 Vue.js is a progressive, incrementally-adoptable JavaScript framework for building UI on the web.
TypeScript is a superset of JavaScript that compiles to clean JavaScript output.
An Open Source Machine Learning Framework for Everyone
The Web framework for perfectionists with deadlines.
A PHP framework for web artisans
Bring data to life with SVG, Canvas and HTML. 📊📈🎉
JavaScript (JS) is a lightweight interpreted programming language with first-class functions.
Some thing interesting about web. New door for the world.
A server is a program made to process requests and deliver data to clients.
Machine learning is a way of modeling and interpreting data that allows a piece of software to respond intelligently.
Some thing interesting about visualization, use data art
Some thing interesting about game, make everyone happy.
We are working to build community through open source technology. NB: members must have two-factor auth.
Open source projects and samples from Microsoft.
Google ❤️ Open Source for everyone.
Alibaba Open Source for everyone
Data-Driven Documents codes.
China tencent open source team.