pem_test.go 9.9 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376
  1. /*
  2. Copyright © The ESO Authors
  3. Licensed under the Apache License, Version 2.0 (the "License");
  4. you may not use this file except in compliance with the License.
  5. You may obtain a copy of the License at
  6. https://www.apache.org/licenses/LICENSE-2.0
  7. Unless required by applicable law or agreed to in writing, software
  8. distributed under the License is distributed on an "AS IS" BASIS,
  9. WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
  10. See the License for the specific language governing permissions and
  11. limitations under the License.
  12. */
  13. package template
  14. import (
  15. "os"
  16. "testing"
  17. )
  18. const (
  19. certData = `-----BEGIN CERTIFICATE-----
  20. MIIDHTCCAgWgAwIBAgIRAKC4yxy9QGocND+6avTf7BgwDQYJKoZIhvcNAQELBQAw
  21. EjEQMA4GA1UEChMHQWNtZSBDbzAeFw0yMTAzMjAyMDA4MDhaFw0yMTAzMjAyMDM4
  22. MDhaMBIxEDAOBgNVBAoTB0FjbWUgQ28wggEiMA0GCSqGSIb3DQEBAQUAA4IBDwAw
  23. ggEKAoIBAQC3o6/JdZEqNbqNRkopHhJtJG5c4qS5d0tQ/kZYpfD/v/izAYum4Nzj
  24. aG15owr92/11W0pxPUliRLti3y6iScTs+ofm2D7p4UXj/Fnho/2xoWSOoWAodgvW
  25. Y8jh8A0LQALZiV/9QsrJdXZdS47DYZLsQ3z9yFC/CdXkg1l7AQ3fIVGKdrQBr9kE
  26. 1gEDqnKfRxXI8DEQKXr+CKPUwCAytegmy0SHp53zNAvY+kopHytzmJpXLoEhxq4e
  27. ugHe52vXHdh/HJ9VjNp0xOH1waAgAGxHlltCW0PVd5AJ0SXROBS/a3V9sZCbCrJa
  28. YOOonQSEswveSv6PcG9AHvpNPot2Xs6hAgMBAAGjbjBsMA4GA1UdDwEB/wQEAwIC
  29. pDATBgNVHSUEDDAKBggrBgEFBQcDATAPBgNVHRMBAf8EBTADAQH/MB0GA1UdDgQW
  30. BBR00805mrpoonp95RmC3B6oLl+cGTAVBgNVHREEDjAMggpnb29ibGUuY29tMA0G
  31. CSqGSIb3DQEBCwUAA4IBAQAipc1b6JrEDayPjpz5GM5krcI8dCWVd8re0a9bGjjN
  32. ioWGlu/eTr5El0ffwCNZ2WLmL9rewfHf/bMvYz3ioFZJ2OTxfazqYXNggQz6cMfa
  33. lbedDCdt5XLVX2TyerGvFram+9Uyvk3l0uM7rZnwAmdirG4Tv94QRaD3q4xTj/c0
  34. mv+AggtK0aRFb9o47z/BypLdk5mhbf3Mmr88C8XBzEnfdYyf4JpTlZrYLBmDCu5d
  35. 9RLLsjXxhag8xqMtd1uLUM8XOTGzVWacw8iGY+CTtBKqyA+AE6/bDwZvEwVtsKtC
  36. QJ85ioEpy00NioqcF0WyMZH80uMsPycfpnl5uF7RkW8u
  37. -----END CERTIFICATE-----
  38. `
  39. otherCert = `-----BEGIN CERTIFICATE-----
  40. MIIBqjCCAU+gAwIBAgIRAPnGGsBUMbZhmh5QdnYdBmUwCgYIKoZIzj0EAwIwGjEY
  41. MBYGA1UEAxMPaW50ZXJtZWRpYXRlLWNhMB4XDTIyMDIwOTEwMjUzMVoXDTIyMDIx
  42. MDEwMjUzMVowDjEMMAoGA1UEAxMDZm9vMFkwEwYHKoZIzj0CAQYIKoZIzj0DAQcD
  43. QgAEqnxdeInykx8JZsLi13rZLekoG2cosQ3F+2InVNy7hCQ7soMqdaJsGQ6LFtov
  44. ogUFtOOTRWrunblqNWGZsowHbKOBgTB/MA4GA1UdDwEB/wQEAwIHgDAdBgNVHSUE
  45. FjAUBggrBgEFBQcDAQYIKwYBBQUHAwIwHQYDVR0OBBYEFLtundVbuKd73OWzo6SY
  46. by0Ajeb2MB8GA1UdIwQYMBaAFCLg80J/bZBbOd+Y8+V94l5xM2zEMA4GA1UdEQQH
  47. MAWCA2ZvbzAKBggqhkjOPQQDAgNJADBGAiEA4K4SbVNqrEtl7RfwBfJFMnWI+X8D
  48. zMPMc4Xqzp2qTxcCIQDsySgtiakypZfWakpB49zJph0kLwGK8xhWvGMUw1N1/w==
  49. -----END CERTIFICATE-----
  50. `
  51. keyData = `-----BEGIN PRIVATE KEY-----
  52. MIIEvwIBADANBgkqhkiG9w0BAQEFAASCBKkwggSlAgEAAoIBAQC3o6/JdZEqNbqN
  53. RkopHhJtJG5c4qS5d0tQ/kZYpfD/v/izAYum4NzjaG15owr92/11W0pxPUliRLti
  54. 3y6iScTs+ofm2D7p4UXj/Fnho/2xoWSOoWAodgvWY8jh8A0LQALZiV/9QsrJdXZd
  55. S47DYZLsQ3z9yFC/CdXkg1l7AQ3fIVGKdrQBr9kE1gEDqnKfRxXI8DEQKXr+CKPU
  56. wCAytegmy0SHp53zNAvY+kopHytzmJpXLoEhxq4eugHe52vXHdh/HJ9VjNp0xOH1
  57. waAgAGxHlltCW0PVd5AJ0SXROBS/a3V9sZCbCrJaYOOonQSEswveSv6PcG9AHvpN
  58. Pot2Xs6hAgMBAAECggEACTGPrmVNZDCWa1Y2hkJ0J7SoNcw+9O4M/jwMp4l/PD6P
  59. I98S78LYLCZhPLK17SmjUcnFO1AXKW1JeFS2D/fjfP256guvcqQNjLFoioxcOhVb
  60. ZGyd1Mi8JPqP5wfOj16gBeYDwTkjz9wqldcfiZaL9XoXetkZecbzR2JwC2FtIVuC
  61. 0njTjMNYpaBKnoLb8OTR0EQz7lYEo2MkQiWryz8wseONnFmdfh18p+p10YgCbuCH
  62. qesrWfDLLxaxZelNtDhDngg9LoCLmarYy7BgShacmUEgJTZ/x3xFC75thK3ln0OY
  63. +ktTgvVotYYaZi7qAjQiEsTvkTAPg5RMpQLd2UIWsQKBgQDCBp+1vURbwGzmTNUg
  64. HMipD6WDFdLc9DCacx6+ZqsEPTMWQbCpVZrDKiY0Rjt5F+xOCyMr00J5RDJXRC0G
  65. +L7NcJdywOFutT7vB+cmETg7l/6PHweNYBnE66706eTL/KVYZMi4tEinarPWhHmL
  66. jasfdLANtpDjdWkRt299TkPRbQKBgQDyS8Rr7KZdv04Csqkf+ASmiJpT5R6Y72kc
  67. 3XYpKETyB2FyPZkuh/zInMut9SkkSI9O/jA3zf956jj6sF1DHvp7T8KkIp5OAQeD
  68. J9AF65m2MnZfHFUeJ6ZQsggwMWqrD0ycIWP7YWtiBHH+D1wGkjYrssq+bvG/yNpA
  69. LtqdKq9lhQKBgQCZA2hIhy61vRckuEsLvCdzTGeW7UsR/XGnHEqOlaEhArKbRsrv
  70. gBdA+qiOaSTV5svw8E+YbE7sG6AnuhhYeyreEYEeeoZOLJmpIG5mUwYp2UBj1nC6
  71. SaOI7OVZOGu7g09SWokBQQxbG4cgEfFY4Sym7fs5lVTGTP3Dfwppo6NQMQKBgQCo
  72. J5NDP3Lafwk58BpV+H/pv8YzUUDh7M2rXbtCpxLqUdr8OOnVlEUISWFF8m5CIyVq
  73. MhjuscWLK9Wtjba7/YTjDaDM3sW05xv6lyfU5ATCoNTr/zLHgcb4HAZ4w+L+otiN
  74. RtMnxB2NYf5mzuwUF2cG/secUEzwyAlIH/xStSwTLQKBgQCRvqF+rqxnegoOgwVW
  75. qrWPv06wXD8dW2FlPpY5GXqA0l6erSK3YsQQToRmbem9ibPD7bd5P4gNbWfxwK4C
  76. Wt+1Rcb8OrDhDJbYz85bXBnPecKp4EN0b9SHO0/dsCqn2w30emc+9T/4m1ZDkpBd
  77. BixHvI/EJ8YK3ta5WdJWKC6hnA==
  78. -----END PRIVATE KEY-----
  79. `
  80. )
  81. const (
  82. filterPrivateKey = "private key"
  83. filterCert = "certificate"
  84. )
  85. func TestFilterPEM(t *testing.T) {
  86. type args struct {
  87. input string
  88. pemType string
  89. }
  90. tests := []struct {
  91. name string
  92. args args
  93. want string
  94. wantErr bool
  95. }{
  96. {
  97. name: "extract cert / cert first",
  98. args: args{
  99. input: certData + keyData,
  100. pemType: filterCert,
  101. },
  102. want: certData,
  103. },
  104. {
  105. name: "extract cert / key first",
  106. args: args{
  107. input: keyData + certData,
  108. pemType: filterCert,
  109. },
  110. want: certData,
  111. },
  112. {
  113. name: "extract multiple certs",
  114. args: args{
  115. input: keyData + certData + keyData + otherCert,
  116. pemType: filterCert,
  117. },
  118. want: certData + otherCert,
  119. },
  120. {
  121. name: "extract key",
  122. args: args{
  123. input: keyData + certData,
  124. pemType: filterPrivateKey,
  125. },
  126. want: keyData,
  127. },
  128. {
  129. name: "key with junk",
  130. args: args{
  131. input: certData + keyData + "some ---junk---",
  132. pemType: filterPrivateKey,
  133. },
  134. want: keyData,
  135. },
  136. {
  137. name: "begin/end with junk",
  138. args: args{
  139. // pem.Decode trims junk from the beginning of the input
  140. // so we are able to decode both cert & key
  141. input: "some junk" + certData + keyData + "some ---junk---",
  142. pemType: filterPrivateKey,
  143. },
  144. want: keyData,
  145. },
  146. {
  147. name: "interleaved junk",
  148. args: args{
  149. // can parse cert but not key due to junk
  150. input: certData + "some junk" + keyData,
  151. pemType: filterPrivateKey,
  152. },
  153. wantErr: true,
  154. },
  155. {
  156. name: "err when junk",
  157. args: args{
  158. input: "---junk---",
  159. pemType: filterPrivateKey,
  160. },
  161. wantErr: true,
  162. },
  163. }
  164. for _, tt := range tests {
  165. t.Run(tt.name, func(t *testing.T) {
  166. got, err := filterPEM(tt.args.pemType, tt.args.input)
  167. if (err != nil) != tt.wantErr {
  168. t.Errorf("filterPEM() error = %v, wantErr %v", err, tt.wantErr)
  169. return
  170. }
  171. if got != tt.want {
  172. t.Errorf("filterPEM() = %v, want %v", got, tt.want)
  173. }
  174. })
  175. }
  176. }
  177. type filterCertChainTestArgs struct {
  178. input []string
  179. certType string
  180. }
  181. type filterCertChainTest struct {
  182. name string
  183. args filterCertChainTestArgs
  184. want string
  185. wantErr bool
  186. }
  187. func TestFilterCertChain(t *testing.T) {
  188. const (
  189. leafCertPath = "_testdata/foo.crt"
  190. intermediateCertPath = "_testdata/intermediate-ca.crt"
  191. rootCertPath = "_testdata/root-ca.crt"
  192. rootKeyPath = "_testdata/root-ca.key"
  193. )
  194. tests := []filterCertChainTest{
  195. {
  196. name: "extract leaf cert / empty cert chain",
  197. args: filterCertChainTestArgs{
  198. input: []string{},
  199. certType: certTypeLeaf,
  200. },
  201. wantErr: true,
  202. },
  203. {
  204. name: "extract leaf cert / cert chain with pkey",
  205. args: filterCertChainTestArgs{
  206. input: []string{
  207. leafCertPath,
  208. rootKeyPath,
  209. },
  210. certType: certTypeLeaf,
  211. },
  212. wantErr: true,
  213. },
  214. {
  215. name: "extract leaf cert / leaf cert only",
  216. args: filterCertChainTestArgs{
  217. input: []string{
  218. leafCertPath,
  219. },
  220. certType: certTypeLeaf,
  221. },
  222. want: leafCertPath,
  223. },
  224. {
  225. name: "extract leaf cert / cert chain without root",
  226. args: filterCertChainTestArgs{
  227. input: []string{
  228. leafCertPath,
  229. intermediateCertPath,
  230. },
  231. certType: certTypeLeaf,
  232. },
  233. want: leafCertPath,
  234. },
  235. {
  236. name: "extract leaf cert / root cert only",
  237. args: filterCertChainTestArgs{
  238. input: []string{
  239. rootCertPath,
  240. },
  241. certType: certTypeLeaf,
  242. },
  243. want: "",
  244. },
  245. {
  246. name: "extract leaf cert / full cert chain",
  247. args: filterCertChainTestArgs{
  248. input: []string{
  249. leafCertPath,
  250. intermediateCertPath,
  251. rootCertPath,
  252. },
  253. certType: certTypeLeaf,
  254. },
  255. want: leafCertPath,
  256. },
  257. {
  258. name: "extract intermediate cert / leaf cert only",
  259. args: filterCertChainTestArgs{
  260. input: []string{
  261. leafCertPath,
  262. },
  263. certType: certTypeIntermediate,
  264. },
  265. want: "",
  266. },
  267. {
  268. name: "extract intermediate cert / cert chain without root",
  269. args: filterCertChainTestArgs{
  270. input: []string{
  271. leafCertPath,
  272. intermediateCertPath,
  273. },
  274. certType: certTypeIntermediate,
  275. },
  276. want: intermediateCertPath,
  277. },
  278. {
  279. name: "extract intermediate cert / full cert chain",
  280. args: filterCertChainTestArgs{
  281. input: []string{
  282. leafCertPath,
  283. intermediateCertPath,
  284. rootCertPath,
  285. },
  286. certType: certTypeIntermediate,
  287. },
  288. want: intermediateCertPath,
  289. },
  290. {
  291. name: "extract root cert / leaf cert only",
  292. args: filterCertChainTestArgs{
  293. input: []string{
  294. leafCertPath,
  295. },
  296. certType: certTypeRoot,
  297. },
  298. want: "",
  299. },
  300. {
  301. name: "extract root cert / root cert only",
  302. args: filterCertChainTestArgs{
  303. input: []string{
  304. rootCertPath,
  305. },
  306. certType: certTypeRoot,
  307. },
  308. want: rootCertPath,
  309. },
  310. {
  311. name: "extract root cert / full cert chain",
  312. args: filterCertChainTestArgs{
  313. input: []string{
  314. leafCertPath,
  315. intermediateCertPath,
  316. rootCertPath,
  317. },
  318. certType: certTypeRoot,
  319. },
  320. want: rootCertPath,
  321. },
  322. }
  323. for _, tt := range tests {
  324. runFilterCertChainTest(t, tt)
  325. }
  326. }
  327. func runFilterCertChainTest(t *testing.T, tt filterCertChainTest) {
  328. t.Run(tt.name, func(t *testing.T) {
  329. chainIn, err := readCertificates(tt.args.input)
  330. if err != nil {
  331. t.Error(err)
  332. }
  333. var expOut []byte
  334. if tt.want != "" {
  335. var err error
  336. expOut, err = os.ReadFile(tt.want)
  337. if err != nil {
  338. t.Error(err)
  339. }
  340. }
  341. got, err := filterCertChain(tt.args.certType, string(chainIn))
  342. if (err != nil) != tt.wantErr {
  343. t.Errorf("filterCertChain() error = %v, wantErr %v", err, tt.wantErr)
  344. return
  345. }
  346. if got != string(expOut) {
  347. t.Errorf("filterCertChain() = %v, want %v", got, string(expOut))
  348. }
  349. })
  350. }
  351. func readCertificates(certFiles []string) ([]byte, error) {
  352. var certificates []byte
  353. for _, f := range certFiles {
  354. c, err := os.ReadFile(f)
  355. if err != nil {
  356. return nil, err
  357. }
  358. certificates = append(certificates, c...)
  359. }
  360. return certificates, nil
  361. }