Skip to content

Commit a555994

Browse files
authored
Merge pull request #287 from anovik/ecdsa
adbe.pkcs7.detached signature example with ECDSA key.
2 parents 2bb80d4 + 911ef42 commit a555994

File tree

7 files changed

+149
-11
lines changed

7 files changed

+149
-11
lines changed

.github/workflows/go.yml

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -24,7 +24,7 @@ jobs:
2424

2525
- name: Setup ImageMagick's MagickWand
2626
run:
27-
sudo apt-get install libmagickwand-dev imagemagick
27+
sudo apt-get update && sudo apt-get install libmagickwand-dev imagemagick
2828

2929
- name: Build all
3030
run: |

accessibility/pdf_add_image_alt_text.go

Lines changed: 8 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -49,7 +49,7 @@ func main() {
4949

5050
// Construct base K dictionary.
5151
docK := model.NewKDictionary()
52-
docK.S = core.MakeName(model.StructureTypeDocument)
52+
docK.S = core.MakeName(string(model.StructureTypeDocument))
5353
// Manually set optional ID for the K object
5454
docK.ID = core.MakeString(kIds[0])
5555
// Or generate the ID automatically using the following:
@@ -62,7 +62,7 @@ func main() {
6262
pageMarkedContentSection := model.NewKDictionary()
6363

6464
// Set the structure type to Section.
65-
pageMarkedContentSection.S = core.MakeName(model.StructureTypeSection)
65+
pageMarkedContentSection.S = core.MakeName(string(model.StructureTypeSection))
6666
pageMarkedContentSection.ID = core.MakeString(kIds[1])
6767

6868
// Add as a child
@@ -105,7 +105,12 @@ func addImage(c *creator.Creator, imageFile string, x, y float64, mcid int64, al
105105
}
106106

107107
// Add the image to the marked content section.
108-
altKdictEntry := img.SetMarkedContentID(mcid)
108+
img.SetMarkedContentID(mcid)
109+
110+
altKdictEntry, err := img.GenerateKDict()
111+
if err != nil {
112+
fmt.Errorf("Error: %v", err)
113+
}
109114

110115
// Set the alternate text.
111116
altKdictEntry.Alt = core.MakeString(altText)

accessibility/pdf_copy_page_with_accessibility.go

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -65,7 +65,7 @@ func main() {
6565

6666
// Construct base K dictionary.
6767
docK := model.NewKDictionary()
68-
docK.S = core.MakeName(model.StructureTypeDocument)
68+
docK.S = core.MakeName(string(model.StructureTypeDocument))
6969

7070
newStr.AddKDict(docK)
7171

@@ -115,7 +115,7 @@ func main() {
115115

116116
// Add section K object to store all original K objects from template page.
117117
sectK := model.NewKDictionary()
118-
sectK.S = core.MakeName(model.StructureTypeSection)
118+
sectK.S = core.MakeName(string(model.StructureTypeSection))
119119
sectK.T = core.MakeString(fmt.Sprintf("Page %d", n))
120120
sectK.GenerateRandomID()
121121

accessibility/pdf_set_language_identifier.go

Lines changed: 13 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -47,7 +47,7 @@ func main() {
4747

4848
// Construct base K dictionary.
4949
docK := model.NewKDictionary()
50-
docK.S = core.MakeName(model.StructureTypeDocument)
50+
docK.S = core.MakeName(string(model.StructureTypeDocument))
5151

5252
str.AddKDict(docK)
5353

@@ -57,7 +57,12 @@ func main() {
5757
p.SetPos(100, 100)
5858

5959
// Set marked content identifier for the paragraph.
60-
pMarkedContent := p.SetMarkedContentID(0)
60+
p.SetMarkedContentID(0)
61+
62+
pMarkedContent, err := p.GenerateKDict()
63+
if err != nil {
64+
fmt.Errorf("Error: %v", err)
65+
}
6166

6267
// Set the language identifier for the paragraph to British English.
6368
pMarkedContent.Lang = core.MakeString("en-GB")
@@ -76,7 +81,11 @@ func main() {
7681
// It's "Hello World" in Indonesian.
7782
sp.SetText("Halo Dunia")
7883
sp.SetPos(100, 200)
79-
pMarkedContent = sp.SetMarkedContentID(1)
84+
sp.SetMarkedContentID(1)
85+
pMarkedContent, err = p.GenerateKDict()
86+
if err != nil {
87+
fmt.Errorf("Error: %v", err)
88+
}
8089

8190
// Set the language identifier for the styled paragraph to Indonesian.
8291
pMarkedContent.Lang = core.MakeString("id-ID")
@@ -88,7 +97,7 @@ func main() {
8897

8998
c.SetStructTreeRoot(str)
9099

91-
err := c.WriteToFile("pdf_set_language_identifier.pdf")
100+
err = c.WriteToFile("pdf_set_language_identifier.pdf")
92101
if err != nil {
93102
fmt.Errorf("Error: %v", err)
94103
}

go.mod

Lines changed: 2 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -13,7 +13,7 @@ require (
1313
github.com/unidoc/globalsign-dss v0.0.0-20220330092912-b69d85b63736
1414
github.com/unidoc/pkcs7 v0.2.0
1515
github.com/unidoc/unichart v0.4.0
16-
github.com/unidoc/unipdf/v4 v4.1.0
16+
github.com/unidoc/unipdf/v4 v4.2.0
1717
golang.org/x/crypto v0.33.0
1818
golang.org/x/image v0.24.0
1919
golang.org/x/text v0.22.0
@@ -70,4 +70,5 @@ require (
7070
google.golang.org/grpc v1.64.1 // indirect
7171
gopkg.in/check.v1 v1.0.0-20201130134442-10cb98267c6c // indirect
7272
gopkg.in/yaml.v3 v3.0.1 // indirect
73+
software.sslmate.com/src/go-pkcs12 v0.6.0 // indirect
7374
)

go.sum

Lines changed: 4 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -131,6 +131,8 @@ github.com/unidoc/unichart v0.4.0 h1:uXk9ZjbqzKb8Lt2Qv2oM9D2ftNRXvezPevgxQhsTQys
131131
github.com/unidoc/unichart v0.4.0/go.mod h1:9QsE8RbS0fE7ndHNroeCEFkRPqqk47Qsoj6QSAtcwN0=
132132
github.com/unidoc/unipdf/v4 v4.1.0 h1:qeEUEVm0rVPocIGZdKoSsRCUTrA3RD+VlBQX7NnP/kY=
133133
github.com/unidoc/unipdf/v4 v4.1.0/go.mod h1:SbSYFUoutyBR+hLlsHyNiCzzcSVVuG10S5Xu8RIJ6EY=
134+
github.com/unidoc/unipdf/v4 v4.2.0 h1:nMBQMOp8WDmm0L1fAdPKZ57pVNloxG+JHClXucwufLo=
135+
github.com/unidoc/unipdf/v4 v4.2.0/go.mod h1:csApn6iwjybsHb43/6BSXAubkSumZ7et0zlcIpJ4iXI=
134136
github.com/unidoc/unitype v0.5.1 h1:UwTX15K6bktwKocWVvLoijIeu4JAVEAIeFqMOjvxqQs=
135137
github.com/unidoc/unitype v0.5.1/go.mod h1:3dxbRL+f1otNqFQIRHho8fxdg3CcUKrqS8w1SXTsqcI=
136138
go.opencensus.io v0.24.0 h1:y73uSU6J157QMP2kn2r30vwW1A2W2WFwSCGnAVxeaD0=
@@ -238,3 +240,5 @@ gopkg.in/yaml.v3 v3.0.1 h1:fxVm/GzAzEWqLHuvctI91KS9hhNmmWOoWu0XTYJS7CA=
238240
gopkg.in/yaml.v3 v3.0.1/go.mod h1:K4uyk7z7BCEPqu6E+C64Yfv1cQ7kz7rIZviUmN+EgEM=
239241
honnef.co/go/tools v0.0.0-20190102054323-c2f93a96b099/go.mod h1:rf3lG4BRIbNafJWhAfAdb/ePZxsR/4RtNHQocxwk9r4=
240242
honnef.co/go/tools v0.0.0-20190523083050-ea95bdfd59fc/go.mod h1:rf3lG4BRIbNafJWhAfAdb/ePZxsR/4RtNHQocxwk9r4=
243+
software.sslmate.com/src/go-pkcs12 v0.6.0 h1:f3sQittAeF+pao32Vb+mkli+ZyT+VwKaD014qFGq6oU=
244+
software.sslmate.com/src/go-pkcs12 v0.6.0/go.mod h1:Qiz0EyvDRJjjxGyUQa2cCNZn/wMyzrRJ/qcDXOQazLI=

signatures/pdf_sign_pkcs7_ecdsa.go

Lines changed: 119 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,119 @@
1+
/*
2+
* This example showcases how to create an adbe.pkcs7.detached compatible digital signature for a PDF file
3+
* using ECDSA (elliptic curve DSA) key. ECDSA keys can be used for signing PDF files starting from version 2.0.
4+
*
5+
* $ ./pdf_sign_pkcs7_ecdsa <FILE.PFX> <PASSWORD> <INPUT_PDF_PATH> <OUTPUT_PDF_PATH>
6+
*/
7+
package main
8+
9+
import (
10+
"crypto/ecdsa"
11+
"fmt"
12+
"log"
13+
"os"
14+
"time"
15+
16+
"github.com/unidoc/unipdf/v4/annotator"
17+
"github.com/unidoc/unipdf/v4/common/license"
18+
"github.com/unidoc/unipdf/v4/core"
19+
"github.com/unidoc/unipdf/v4/model"
20+
"github.com/unidoc/unipdf/v4/model/sighandler"
21+
22+
"software.sslmate.com/src/go-pkcs12"
23+
)
24+
25+
func init() {
26+
// Make sure to load your metered License API key prior to using the library.
27+
// If you need a key, you can sign up and create a free one at https://cloud.unidoc.io
28+
err := license.SetMeteredKey(os.Getenv(`UNIDOC_LICENSE_API_KEY`))
29+
if err != nil {
30+
panic(err)
31+
}
32+
}
33+
34+
const usagef = "Usage: %s PFX_FILE PASSWORD INPUT_PDF_PATH OUTPUT_PDF_PATH\n"
35+
36+
func main() {
37+
args := os.Args
38+
if len(args) < 5 {
39+
fmt.Printf(usagef, os.Args[0])
40+
return
41+
}
42+
pfxPath := args[1]
43+
password := args[2]
44+
inputPath := args[3]
45+
outputPath := args[4]
46+
47+
// Get private key and X509 certificate from the ECDSA PFX file.
48+
pfxData, err := os.ReadFile(pfxPath)
49+
if err != nil {
50+
log.Fatal("Fail: %v\n", err)
51+
}
52+
53+
priv, cert, err := pkcs12.Decode(pfxData, password)
54+
if err != nil {
55+
log.Fatal("Fail: %v\n", err)
56+
}
57+
58+
// Create reader.
59+
file, err := os.Open(inputPath)
60+
if err != nil {
61+
log.Fatal("Fail: %v\n", err)
62+
}
63+
defer file.Close()
64+
65+
reader, err := model.NewPdfReader(file)
66+
if err != nil {
67+
log.Fatal("Fail: %v\n", err)
68+
}
69+
70+
// Create appender.
71+
appender, err := model.NewPdfAppender(reader)
72+
if err != nil {
73+
log.Fatal("Fail: %v\n", err)
74+
}
75+
76+
// Create signature handler with ECDSA key.
77+
handler, err := sighandler.NewAdobePKCS7DetachedEcdsa(priv.(*ecdsa.PrivateKey), cert)
78+
if err != nil {
79+
log.Fatal("Fail: %v\n", err)
80+
}
81+
82+
// Create signature.
83+
signature := model.NewPdfSignature(handler)
84+
signature.SetName("adbe.pkcs7.detached ECDSA PDF")
85+
signature.SetReason("Test ECDSA")
86+
signature.SetDate(time.Now(), "")
87+
88+
if err := signature.Initialize(); err != nil {
89+
log.Fatal("Fail: %v\n", err)
90+
}
91+
92+
// Create signature field and appearance.
93+
opts := annotator.NewSignatureFieldOpts()
94+
opts.FontSize = 10
95+
opts.Rect = []float64{10, 25, 75, 60}
96+
97+
field, err := annotator.NewSignatureField(
98+
signature,
99+
[]*annotator.SignatureLine{
100+
annotator.NewSignatureLine("Name", "John Doe"),
101+
annotator.NewSignatureLine("Date", "2025.07.28"),
102+
annotator.NewSignatureLine("Reason", "Test"),
103+
},
104+
opts,
105+
)
106+
field.T = core.MakeString("Self signed PDF")
107+
108+
if err = appender.Sign(1, field); err != nil {
109+
log.Fatal("Fail: %v\n", err)
110+
}
111+
112+
// Write output PDF file.
113+
err = appender.WriteToFile(outputPath)
114+
if err != nil {
115+
log.Fatal("Fail: %v\n", err)
116+
}
117+
118+
log.Printf("PDF file successfully signed. Output path: %s\n", outputPath)
119+
}

0 commit comments

Comments
 (0)