Sign pdf files in Go (Golang) using digitalorus/pdfsign
Signing PDF files in Go language is a common need, and this function can be easily achieved using the digitalorus/pdfsign library. PHP editor Youzi will introduce you to how to use this library. Whether in business applications or personal projects, signing PDF files is a common operation. The digitalorus/pdfsign library provides a simple and easy-to-use interface, making signing PDF files in Go language simple and fast. Through this article, you will learn how to use the digitalorus/pdfsign library in the Go language to complete the signing operation of PDF files. Let’s explore together!
Question content
In go (golang), I need to sign a pdf document, but unlike other languages, there isn't any library that makes the job easier. I found a few paid ones, but they weren't an option.
First, I have a PKCS certificate (.p12) from which I have extracted the private key and x509 certificate using this package: https://pkg.go.dev/software.sslmate.com/src/go -pkcs12
But when I want to sign a pdf document, I'm stuck because I don't know how to properly pass parameters to a function that does such an operation. The package used is https://pkg.go.dev/github.com/digitorus/pdfsign
My complete code is:
package main import ( "crypto" "fmt" "os" "time" "github.com/digitorus/pdf" "github.com/digitorus/pdfsign/revocation" "github.com/digitorus/pdfsign/sign" gopkcs12 "software.sslmate.com/src/go-pkcs12" ) func main() { certBytes, err := os.ReadFile("certificate.p12") if err != nil { fmt.Println(err) return } privateKey, certificate, chainCerts, err := gopkcs12.DecodeChain(certBytes, "MyPassword") if err != nil { fmt.Println(err) return } input_file, err := os.Open("input-file.pdf") if err != nil { fmt.Println(err) return } defer input_file.Close() output_file, err := os.Create("output-file.pdf") if err != nil { fmt.Println(err) return } defer output_file.Close() finfo, err := input_file.Stat() if err != nil { fmt.Println(err) return } size := finfo.Size() rdr, err := pdf.NewReader(input_file, size) if err != nil { fmt.Println(err) return } err = sign.Sign(input_file, output_file, rdr, size, sign.SignData{ Signature: sign.SignDataSignature{ Info: sign.SignDataSignatureInfo{ Name: "John Doe", Location: "Somewhere on the globe", Reason: "My season for siging this document", ContactInfo: "How you like", Date: time.Now().Local(), }, CertType: sign.CertificationSignature, DocMDPPerm: sign.AllowFillingExistingFormFieldsAndSignaturesPerms, }, Signer: privateKey, // crypto.Signer DigestAlgorithm: crypto.SHA256, // hash algorithm for the digest creation Certificate: certificate, // x509.Certificate CertificateChains: chainCerts, // x509.Certificate.Verify() TSA: sign.TSA{ URL: "https://freetsa.org/tsr", Username: "", Password: "", }, // The follow options are likely to change in a future release // // cache revocation data when bulk signing RevocationData: revocation.InfoArchival{}, // custom revocation lookup RevocationFunction: sign.DefaultEmbedRevocationStatusFunction, }) if err != nil { fmt.Println(err) } else { fmt.Println("Signed PDF written to output.pdf") } }
To be precise, they are the Signer and CertificateChains parameters of my question. I don't know how to use privateKey and chainCerts variables correctly.
The message error is:
- Cannot use privateKey (variable of type interface{}) as a crypto.Signer value in a struct literal: interface{} does not implement crypto.Signer (missing Public method)
- Unable to use chainCertificates (variable of type []*x509.Certificate) as the [][]*x509.Certificate value in a structure literal
I'm new to this language, so I still don't understand the in-depth concepts and data types.
Thanks for telling me what else I should do or what steps are missing to be successful. Or if anyone knows how I can sign a pdf based on a pkcs certificate.
Workaround
Signing a PDF using a digital signature involves generating a pair of keys using public key cryptography. The private key is used to encrypt the data related to the signature and only the signer can access it, while the public key is used to decrypt the signature data for verification. If it is not issued by a trusted certificate authority, the said public key certificate must Add it to the certificate store to make it trusted. In the given example, this signature data is stored inside a structure called sign.SignData, which is part of the pdfsign library and requires an x509 certificate and a signer that implements the crypto.Signer interface.
The first step is to generate a pair of keys using the crypto/ecdsa package in the Go standard library. GenerateKey will save the private and public keys into the privateKey variable. This returned privateKey variable implements the crypto.Signer interface, which is required to solve the problem you are currently facing.
You can check this by reading line 142 of the ecdsa.go code.
You are currently using gopkcs12.DecodeChain to return the private key, but it does not implement the crypto.Signer interface, so you will get an error. You may need to implement a custom one, but that's another question.
concept:
ECDSA stands for Elliptic Curve Digital Signature Algorithm. It is a public key encryption algorithm used for digital signatures. See the Go standard library documentation and the NIST website for more information.
- https://pkg.go.dev/crypto/[email protected]
- https://www.php.cn/link/813b6a28cc4ac72d244266161e3e2eb4
NIST P-384: P-384 is one of the elliptic curves recommended by the National Institute of Standards and Technology (NIST) with a key length of 384 bits. For more information about digital signatures and more recommended elliptic curves, see the NIST website. I use the P-384 as a working solution.
- https://nvlpubs.nist.gov/nistpubs /FIPS/NIST.FIPS.186-4.pdf
- https://www.php.cn/link/73c66ed635c83ba1316b28524a31b12f
- https://csrc.nist.gov/pubs/fips/186 -4/国际泳联
第二步是使用Go标准库中的crypto/x509包通过其链生成器生成x509证书和证书链。这些是您在问题中寻求帮助的特定变量,但不属于您在错误消息中可以清楚看到的预期类型。只需遵循 lib 指令并使用 x509.Certificate.Verify() 就像我在工作解决方案中所做的那样,这将返回正确的类型 [][]*x509.Certificate。
请参阅 Go 标准库文档以获取更多信息。
- https://www.php.cn/link/92d1e1eb1cd6f9fba3227870bb6d7f07
- https://www.php.cn/link/54d2e69c08f60ae7c37f509f962c59a8一个>
- https://www.php.cn/link/6afd3a1bbb557f8e05f45ded7bf96836
第三步是打开输入 pdf 文件并使用 Go 标准库中的 os 包创建输出 pdf 文件。
第四步实际上是使用 digitalorus/pdfsign 库对 pdf 文件进行签名。
这是我今天编码和测试的一个有效解决方案,旨在让您回到正轨,进行一些研究并根据您的需求进行修改:
package main import ( "crypto" "crypto/ecdsa" "crypto/elliptic" "crypto/rand" "crypto/x509" "crypto/x509/pkix" "fmt" "github.com/digitorus/pdf" "github.com/digitorus/pdfsign/revocation" "github.com/digitorus/pdfsign/sign" "log" "math/big" "os" "time" ) func main() { // First step privateKey, err := ecdsa.GenerateKey(elliptic.P384(), rand.Reader) if err != nil { panic(err) } // Second step x509RootCertificate := &x509.Certificate{ SerialNumber: big.NewInt(2023), Subject: pkix.Name{ Organization: []string{"Your Organization"}, Country: []string{"Your Country"}, Province: []string{"Your Province"}, Locality: []string{"Your Locality"}, StreetAddress: []string{"Your Street Address"}, PostalCode: []string{"Your Postal Code"}, }, NotBefore: time.Now(), NotAfter: time.Now().AddDate(10, 0, 0), IsCA: true, ExtKeyUsage: []x509.ExtKeyUsage{x509.ExtKeyUsageClientAuth, x509.ExtKeyUsageServerAuth}, KeyUsage: x509.KeyUsageDigitalSignature | x509.KeyUsageCertSign, BasicConstraintsValid: true, } rootCertificateBytes, err := x509.CreateCertificate(rand.Reader, x509RootCertificate, x509RootCertificate, &privateKey.PublicKey, privateKey) if err != nil { panic(err) } rootCertificate, err := x509.ParseCertificate(rootCertificateBytes) if err != nil { panic(err) } roots := x509.NewCertPool() roots.AddCert(rootCertificate) certificateChain, err := rootCertificate.Verify(x509.VerifyOptions{ Roots: roots, }) if err != nil { panic(err) } // Third step outputFile, err := os.Create("output.pdf") if err != nil { panic(err) } defer func(outputFile *os.File) { err = outputFile.Close() if err != nil { log.Println(err) } fmt.Println("output file closed") }(outputFile) inputFile, err := os.Open("input.pdf") if err != nil { panic(err) } defer func(inputFile *os.File) { err = inputFile.Close() if err != nil { log.Println(err) } fmt.Println("input file closed") }(inputFile) fileInfo, err := inputFile.Stat() if err != nil { panic(err) } size := fileInfo.Size() pdfReader, err := pdf.NewReader(inputFile, size) if err != nil { panic(err) } // Fourth step err = sign.Sign(inputFile, outputFile, pdfReader, size, sign.SignData{ Signature: sign.SignDataSignature{ Info: sign.SignDataSignatureInfo{ Name: "Your name", Location: "Your location", Reason: "Your reason", ContactInfo: "Your contact info", Date: time.Now().Local(), }, CertType: sign.CertificationSignature, DocMDPPerm: sign.AllowFillingExistingFormFieldsAndSignaturesPerms, }, Signer: privateKey, // crypto.Signer DigestAlgorithm: crypto.SHA256, // hash algorithm for the digest creation Certificate: rootCertificate, // x509.Certificate CertificateChains: certificateChain, // x509.Certificate.Verify() TSA: sign.TSA{ URL: "", Username: "", Password: "", }, // The follow options are likely to change in a future release // // cache revocation data when bulk signing RevocationData: revocation.InfoArchival{}, // custom revocation lookup RevocationFunction: sign.DefaultEmbedRevocationStatusFunction, }) if err != nil { log.Println(err) } else { log.Println("pdf signed") } }
结果:
go run main.go 2023/12/01 21:53:37 pdf signed input file closed output file closed
The above is the detailed content of Sign pdf files in Go (Golang) using digitalorus/pdfsign. For more information, please follow other related articles on the PHP Chinese website!

Hot AI Tools

Undresser.AI Undress
AI-powered app for creating realistic nude photos

AI Clothes Remover
Online AI tool for removing clothes from photos.

Undress AI Tool
Undress images for free

Clothoff.io
AI clothes remover

Video Face Swap
Swap faces in any video effortlessly with our completely free AI face swap tool!

Hot Article

Hot Tools

Notepad++7.3.1
Easy-to-use and free code editor

SublimeText3 Chinese version
Chinese version, very easy to use

Zend Studio 13.0.1
Powerful PHP integrated development environment

Dreamweaver CS6
Visual web development tools

SublimeText3 Mac version
God-level code editing software (SublimeText3)

Hot Topics











Multithreading in the language can greatly improve program efficiency. There are four main ways to implement multithreading in C language: Create independent processes: Create multiple independently running processes, each process has its own memory space. Pseudo-multithreading: Create multiple execution streams in a process that share the same memory space and execute alternately. Multi-threaded library: Use multi-threaded libraries such as pthreads to create and manage threads, providing rich thread operation functions. Coroutine: A lightweight multi-threaded implementation that divides tasks into small subtasks and executes them in turn.

Queue threading problem in Go crawler Colly explores the problem of using the Colly crawler library in Go language, developers often encounter problems with threads and request queues. �...

The problem of using RedisStream to implement message queues in Go language is using Go language and Redis...

What should I do if the custom structure labels in GoLand are not displayed? When using GoLand for Go language development, many developers will encounter custom structure tags...

The difference between string printing in Go language: The difference in the effect of using Println and string() functions is in Go...

The library used for floating-point number operation in Go language introduces how to ensure the accuracy is...

There is no function named "sum" in the C language standard library. "sum" is usually defined by programmers or provided in specific libraries, and its functionality depends on the specific implementation. Common scenarios are summing for arrays, and can also be used in other data structures, such as linked lists. In addition, "sum" is also used in fields such as image processing and statistical analysis. An excellent "sum" function should have good readability, robustness and efficiency.

Which libraries in Go are developed by large companies or well-known open source projects? When programming in Go, developers often encounter some common needs, ...
