xmldsign 0.1.0
Sign up to get free protection for your applications and to get access to all the features.
- data/.gitignore +18 -0
- data/.idea/.name +1 -0
- data/.idea/.rakeTasks +7 -0
- data/.idea/encodings.xml +5 -0
- data/.idea/misc.xml +25 -0
- data/.idea/modules.xml +9 -0
- data/.idea/scopes/scope_settings.xml +5 -0
- data/.idea/vcs.xml +7 -0
- data/Gemfile +4 -0
- data/LICENSE.txt +22 -0
- data/README.md +29 -0
- data/Rakefile +1 -0
- data/ext/xmldsign/extconf.rb +3 -0
- data/ext/xmldsign/gost89.c +409 -0
- data/ext/xmldsign/gost89.h +96 -0
- data/ext/xmldsign/gosthash.c +254 -0
- data/ext/xmldsign/gosthash.h +48 -0
- data/ext/xmldsign/xmldsign_ext.bundle +0 -0
- data/ext/xmldsign/xmldsign_ext.c +66 -0
- data/ext/xmldsign/xmldsign_ext.h +18 -0
- data/lib/xmldsign/algorithms.rb +84 -0
- data/lib/xmldsign/digests/gost.rb +30 -0
- data/lib/xmldsign/document.rb +19 -0
- data/lib/xmldsign/error.rb +2 -0
- data/lib/xmldsign/signature.rb +64 -0
- data/lib/xmldsign/signed_info.rb +7 -0
- data/lib/xmldsign/transforms.rb +17 -0
- data/lib/xmldsign/version.rb +3 -0
- data/lib/xmldsign.rb +21 -0
- data/spec/assets/act-birth-for-sign.xml +118 -0
- data/spec/assets/act-birth-with-comment-for-sign.xml +105 -0
- data/spec/assets/act-death-for-sign.xml +75 -0
- data/spec/assets/act-death-with-empty-tags-for-sign.xml +75 -0
- data/spec/assets/csr.pem +11 -0
- data/spec/assets/private.key.pem +15 -0
- data/spec/assets/private.passw.key.pem +18 -0
- data/spec/assets/public.key.pem +6 -0
- data/spec/assets/signed-act-birth-with-comment.xml +134 -0
- data/spec/assets/signed-act-birth.xml +116 -0
- data/spec/assets/signed-act-changed-ns-order.xml +137 -0
- data/spec/assets/signed-act-changed-prefixes.xml +136 -0
- data/spec/assets/signed-act-changed-xml-comments.xml +146 -0
- data/spec/assets/signed-act-death-with-empty-tags.xml +117 -0
- data/spec/assets/signed-act-death.xml +117 -0
- data/spec/assets/signed-act-wrong-canon-alg.xml +34 -0
- data/spec/assets/signed-act-wrong-data.xml +133 -0
- data/spec/assets/signed-act-wrong-sign-alg.xml +34 -0
- data/spec/assets/signed-act-wrong-signature-value.xml +133 -0
- data/spec/assets/signed-act-wrong-trans-alg.xml +34 -0
- data/spec/assets/signed-act-wrong-trans-algs-order.xml +34 -0
- data/spec/assets/signed-act-wrong-trans-count.xml +31 -0
- data/spec/assets/signed-act-wrong-trans0-alg.xml +34 -0
- data/spec/assets/signed-act-wrong-transxslt-alg.xml +34 -0
- data/spec/assets/signed-info-for-act-birth.xml +15 -0
- data/spec/assets/signed.test.xml +103 -0
- data/spec/assets/unsigned.test.xml +14 -0
- data/spec/assets/x509.crt +13 -0
- data/spec/spec_helper.rb +22 -0
- data/spec/xmldsign/sign_spec.rb +24 -0
- data/xmldsign.gemspec +29 -0
- metadata +254 -0
@@ -0,0 +1,254 @@
|
|
1
|
+
/**********************************************************************
|
2
|
+
* gosthash.c *
|
3
|
+
* Copyright (c) 2005-2006 Cryptocom LTD *
|
4
|
+
* This file is distributed under the same license as OpenSSL *
|
5
|
+
* *
|
6
|
+
* Implementation of GOST R 34.11-94 hash function *
|
7
|
+
* uses on gost89.c and gost89.h Doesn't need OpenSSL *
|
8
|
+
**********************************************************************/
|
9
|
+
#include <string.h>
|
10
|
+
|
11
|
+
#include "gost89.h"
|
12
|
+
#include "gosthash.h"
|
13
|
+
|
14
|
+
|
15
|
+
/* Use OPENSSL_malloc for memory allocation if compiled with
|
16
|
+
* -DOPENSSL_BUILD, and libc malloc otherwise
|
17
|
+
*/
|
18
|
+
#ifndef MYALLOC
|
19
|
+
# ifdef OPENSSL_BUILD
|
20
|
+
# include <openssl/crypto.h>
|
21
|
+
# define MYALLOC(size) OPENSSL_malloc(size)
|
22
|
+
# define MYFREE(ptr) OPENSSL_free(ptr)
|
23
|
+
# else
|
24
|
+
# define MYALLOC(size) malloc(size)
|
25
|
+
# define MYFREE(ptr) free(ptr)
|
26
|
+
# endif
|
27
|
+
#endif
|
28
|
+
/* Following functions are various bit meshing routines used in
|
29
|
+
* GOST R 34.11-94 algorithms */
|
30
|
+
static void swap_bytes (byte *w, byte *k)
|
31
|
+
{
|
32
|
+
int i,j;
|
33
|
+
for (i=0;i<4;i++)
|
34
|
+
for (j=0;j<8;j++)
|
35
|
+
k[i+4*j]=w[8*i+j];
|
36
|
+
}
|
37
|
+
|
38
|
+
/* was A_A */
|
39
|
+
static void circle_xor8 (const byte *w, byte *k)
|
40
|
+
{
|
41
|
+
byte buf[8];
|
42
|
+
int i;
|
43
|
+
memcpy(buf,w,8);
|
44
|
+
memcpy(k,w+8,24);
|
45
|
+
for(i=0;i<8;i++)
|
46
|
+
k[i+24]=buf[i]^k[i];
|
47
|
+
}
|
48
|
+
|
49
|
+
/* was R_R */
|
50
|
+
static void transform_3 (byte *data)
|
51
|
+
{
|
52
|
+
unsigned short int acc;
|
53
|
+
acc=(data[0]^data[2]^data[4]^data[6]^data[24]^data[30])|
|
54
|
+
((data[1]^data[3]^data[5]^data[7]^data[25]^data[31])<<8);
|
55
|
+
memmove(data,data+2,30);
|
56
|
+
data[30]=acc&0xff;
|
57
|
+
data[31]=acc>>8;
|
58
|
+
}
|
59
|
+
|
60
|
+
/* Adds blocks of N bytes modulo 2**(8*n). Returns carry*/
|
61
|
+
static int add_blocks(int n,byte *left, const byte *right)
|
62
|
+
{
|
63
|
+
int i;
|
64
|
+
int carry=0;
|
65
|
+
int sum;
|
66
|
+
for (i=0;i<n;i++)
|
67
|
+
{
|
68
|
+
sum=(int)left[i]+(int)right[i]+carry;
|
69
|
+
left[i]=sum & 0xff;
|
70
|
+
carry=sum>>8;
|
71
|
+
}
|
72
|
+
return carry;
|
73
|
+
}
|
74
|
+
|
75
|
+
/* Xor two sequences of bytes */
|
76
|
+
static void xor_blocks (byte *result,const byte *a,const byte *b,size_t len)
|
77
|
+
{
|
78
|
+
size_t i;
|
79
|
+
for (i=0;i<len;i++) result[i]=a[i]^b[i];
|
80
|
+
}
|
81
|
+
|
82
|
+
/*
|
83
|
+
* Calculate H(i+1) = Hash(Hi,Mi)
|
84
|
+
* Where H and M are 32 bytes long
|
85
|
+
*/
|
86
|
+
static int hash_step(gost_ctx *c,byte *H,const byte *M)
|
87
|
+
{
|
88
|
+
byte U[32],W[32],V[32],S[32],Key[32];
|
89
|
+
int i;
|
90
|
+
/* Compute first key */
|
91
|
+
xor_blocks(W,H,M,32);
|
92
|
+
swap_bytes(W,Key);
|
93
|
+
/* Encrypt first 8 bytes of H with first key*/
|
94
|
+
gost_enc_with_key(c,Key,H,S);
|
95
|
+
/* Compute second key*/
|
96
|
+
circle_xor8(H,U);
|
97
|
+
circle_xor8(M,V);
|
98
|
+
circle_xor8(V,V);
|
99
|
+
xor_blocks(W,U,V,32);
|
100
|
+
swap_bytes(W,Key);
|
101
|
+
/* encrypt second 8 bytes of H with second key*/
|
102
|
+
gost_enc_with_key(c,Key,H+8,S+8);
|
103
|
+
/* compute third key */
|
104
|
+
circle_xor8(U,U);
|
105
|
+
U[31]=~U[31]; U[29]=~U[29]; U[28]=~U[28]; U[24]=~U[24];
|
106
|
+
U[23]=~U[23]; U[20]=~U[20]; U[18]=~U[18]; U[17]=~U[17];
|
107
|
+
U[14]=~U[14]; U[12]=~U[12]; U[10]=~U[10]; U[ 8]=~U[ 8];
|
108
|
+
U[ 7]=~U[ 7]; U[ 5]=~U[ 5]; U[ 3]=~U[ 3]; U[ 1]=~U[ 1];
|
109
|
+
circle_xor8(V,V);
|
110
|
+
circle_xor8(V,V);
|
111
|
+
xor_blocks(W,U,V,32);
|
112
|
+
swap_bytes(W,Key);
|
113
|
+
/* encrypt third 8 bytes of H with third key*/
|
114
|
+
gost_enc_with_key(c,Key,H+16,S+16);
|
115
|
+
/* Compute fourth key */
|
116
|
+
circle_xor8(U,U);
|
117
|
+
circle_xor8(V,V);
|
118
|
+
circle_xor8(V,V);
|
119
|
+
xor_blocks(W,U,V,32);
|
120
|
+
swap_bytes(W,Key);
|
121
|
+
/* Encrypt last 8 bytes with fourth key */
|
122
|
+
gost_enc_with_key(c,Key,H+24,S+24);
|
123
|
+
for (i=0;i<12;i++)
|
124
|
+
transform_3(S);
|
125
|
+
xor_blocks(S,S,M,32);
|
126
|
+
transform_3(S);
|
127
|
+
xor_blocks(S,S,H,32);
|
128
|
+
for (i=0;i<61;i++)
|
129
|
+
transform_3(S);
|
130
|
+
memcpy(H,S,32);
|
131
|
+
return 1;
|
132
|
+
}
|
133
|
+
|
134
|
+
/* Initialize gost_hash ctx - cleans up temporary structures and
|
135
|
+
* set up substitution blocks
|
136
|
+
*/
|
137
|
+
int init_gost_hash_ctx(gost_hash_ctx *ctx, const gost_subst_block *subst_block)
|
138
|
+
{
|
139
|
+
memset(ctx,0,sizeof(gost_hash_ctx));
|
140
|
+
ctx->cipher_ctx = (gost_ctx *)MYALLOC(sizeof(gost_ctx));
|
141
|
+
if (!ctx->cipher_ctx)
|
142
|
+
{
|
143
|
+
return 0;
|
144
|
+
}
|
145
|
+
gost_init(ctx->cipher_ctx,subst_block);
|
146
|
+
return 1;
|
147
|
+
}
|
148
|
+
|
149
|
+
/*
|
150
|
+
* Free cipher CTX if it is dynamically allocated. Do not use
|
151
|
+
* if cipher ctx is statically allocated as in OpenSSL implementation of
|
152
|
+
* GOST hash algroritm
|
153
|
+
*
|
154
|
+
*/
|
155
|
+
void done_gost_hash_ctx(gost_hash_ctx *ctx)
|
156
|
+
{
|
157
|
+
/* No need to use gost_destroy, because cipher keys are not really
|
158
|
+
* secret when hashing */
|
159
|
+
MYFREE(ctx->cipher_ctx);
|
160
|
+
}
|
161
|
+
|
162
|
+
/*
|
163
|
+
* reset state of hash context to begin hashing new message
|
164
|
+
*/
|
165
|
+
int start_hash(gost_hash_ctx *ctx)
|
166
|
+
{
|
167
|
+
if (!ctx->cipher_ctx) return 0;
|
168
|
+
memset(&(ctx->H),0,32);
|
169
|
+
memset(&(ctx->S),0,32);
|
170
|
+
ctx->len = 0L;
|
171
|
+
ctx->left=0;
|
172
|
+
return 1;
|
173
|
+
}
|
174
|
+
|
175
|
+
/*
|
176
|
+
* Hash block of arbitrary length
|
177
|
+
*
|
178
|
+
*
|
179
|
+
*/
|
180
|
+
int hash_block(gost_hash_ctx *ctx,const byte *block, size_t length)
|
181
|
+
{
|
182
|
+
const byte *curptr=block;
|
183
|
+
const byte *barrier=block+(length-32);/* Last byte we can safely hash*/
|
184
|
+
if (ctx->left)
|
185
|
+
{
|
186
|
+
/*There are some bytes from previous step*/
|
187
|
+
unsigned int add_bytes = 32-ctx->left;
|
188
|
+
if (add_bytes>length)
|
189
|
+
{
|
190
|
+
add_bytes = length;
|
191
|
+
}
|
192
|
+
memcpy(&(ctx->remainder[ctx->left]),block,add_bytes);
|
193
|
+
ctx->left+=add_bytes;
|
194
|
+
if (ctx->left<32)
|
195
|
+
{
|
196
|
+
return 1;
|
197
|
+
}
|
198
|
+
curptr=block+add_bytes;
|
199
|
+
hash_step(ctx->cipher_ctx,ctx->H,ctx->remainder);
|
200
|
+
add_blocks(32,ctx->S,ctx->remainder);
|
201
|
+
ctx->len+=32;
|
202
|
+
ctx->left=0;
|
203
|
+
}
|
204
|
+
while (curptr<=barrier)
|
205
|
+
{
|
206
|
+
hash_step(ctx->cipher_ctx,ctx->H,curptr);
|
207
|
+
|
208
|
+
add_blocks(32,ctx->S,curptr);
|
209
|
+
ctx->len+=32;
|
210
|
+
curptr+=32;
|
211
|
+
}
|
212
|
+
if (curptr!=block+length)
|
213
|
+
{
|
214
|
+
ctx->left=block+length-curptr;
|
215
|
+
memcpy(ctx->remainder,curptr,ctx->left);
|
216
|
+
}
|
217
|
+
return 1;
|
218
|
+
}
|
219
|
+
|
220
|
+
/*
|
221
|
+
* Compute hash value from current state of ctx
|
222
|
+
* state of hash ctx becomes invalid and cannot be used for further
|
223
|
+
* hashing.
|
224
|
+
*/
|
225
|
+
int finish_hash(gost_hash_ctx *ctx,byte *hashval)
|
226
|
+
{
|
227
|
+
byte buf[32];
|
228
|
+
byte H[32];
|
229
|
+
byte S[32];
|
230
|
+
ghosthash_len fin_len=ctx->len;
|
231
|
+
byte *bptr;
|
232
|
+
memcpy(H,ctx->H,32);
|
233
|
+
memmove(S,ctx->S,32);
|
234
|
+
if (ctx->left)
|
235
|
+
{
|
236
|
+
memset(buf,0,32);
|
237
|
+
memcpy(buf,ctx->remainder,ctx->left);
|
238
|
+
hash_step(ctx->cipher_ctx,H,buf);
|
239
|
+
add_blocks(32,S,buf);
|
240
|
+
fin_len+=ctx->left;
|
241
|
+
}
|
242
|
+
memset(buf,0,32);
|
243
|
+
bptr=buf;
|
244
|
+
fin_len<<=3; /* Hash length in BITS!!*/
|
245
|
+
while(fin_len>0)
|
246
|
+
{
|
247
|
+
*(bptr++)=(byte)(fin_len&0xFF);
|
248
|
+
fin_len>>=8;
|
249
|
+
};
|
250
|
+
hash_step(ctx->cipher_ctx,H,buf);
|
251
|
+
hash_step(ctx->cipher_ctx,H,S);
|
252
|
+
memcpy(hashval,H,32);
|
253
|
+
return 1;
|
254
|
+
}
|
@@ -0,0 +1,48 @@
|
|
1
|
+
/**********************************************************************
|
2
|
+
* gosthash.h *
|
3
|
+
* Copyright (c) 2005-2006 Cryptocom LTD *
|
4
|
+
* This file is distributed under the same license as OpenSSL *
|
5
|
+
* *
|
6
|
+
* Declaration of GOST R 34.11-94 hash functions *
|
7
|
+
* uses and gost89.h Doesn't need OpenSSL *
|
8
|
+
**********************************************************************/
|
9
|
+
#ifndef GOSTHASH_H
|
10
|
+
#define GOSTHASH_H
|
11
|
+
#include "gost89.h"
|
12
|
+
#include <stdlib.h>
|
13
|
+
|
14
|
+
#if (defined(_WIN32) || defined(_WIN64)) && !defined(__MINGW32__)
|
15
|
+
typedef __int64 ghosthash_len;
|
16
|
+
#elif defined(__arch64__)
|
17
|
+
typedef long ghosthash_len;
|
18
|
+
#else
|
19
|
+
typedef long long ghosthash_len;
|
20
|
+
#endif
|
21
|
+
|
22
|
+
typedef struct gost_hash_ctx {
|
23
|
+
ghosthash_len len;
|
24
|
+
gost_ctx *cipher_ctx;
|
25
|
+
int left;
|
26
|
+
byte H[32];
|
27
|
+
byte S[32];
|
28
|
+
byte remainder[32];
|
29
|
+
} gost_hash_ctx;
|
30
|
+
|
31
|
+
|
32
|
+
/* Initalizes gost hash ctx, including creation of gost cipher ctx */
|
33
|
+
|
34
|
+
int init_gost_hash_ctx(gost_hash_ctx *ctx, const gost_subst_block *subst_block);
|
35
|
+
void done_gost_hash_ctx(gost_hash_ctx *ctx);
|
36
|
+
|
37
|
+
/* Cleans up all fields, except cipher ctx preparing ctx for computing
|
38
|
+
* of new hash value */
|
39
|
+
int start_hash(gost_hash_ctx *ctx);
|
40
|
+
|
41
|
+
/* Hashes block of data */
|
42
|
+
int hash_block(gost_hash_ctx *ctx, const byte *block, size_t length);
|
43
|
+
|
44
|
+
/* Finalizes computation of hash and fills buffer (which should be at
|
45
|
+
* least 32 bytes long) with value of computed hash. */
|
46
|
+
int finish_hash(gost_hash_ctx *ctx, byte *hashval);
|
47
|
+
|
48
|
+
#endif
|
Binary file
|
@@ -0,0 +1,66 @@
|
|
1
|
+
#include <xmldsign_ext.h>
|
2
|
+
|
3
|
+
#ifndef O_BINARY
|
4
|
+
#define O_BINARY 0
|
5
|
+
#endif
|
6
|
+
|
7
|
+
char* substring(const char* str, size_t begin, size_t len)
|
8
|
+
{
|
9
|
+
if (str == 0 || strlen(str) == 0 || strlen(str) < begin || strlen(str) < (begin+len))
|
10
|
+
return 0;
|
11
|
+
|
12
|
+
return strndup(str + begin, len);
|
13
|
+
}
|
14
|
+
|
15
|
+
int digest(char * data, char * sum)
|
16
|
+
{
|
17
|
+
gost_subst_block *b= &GostR3411_94_CryptoProParamSet;
|
18
|
+
gost_hash_ctx ctx;
|
19
|
+
|
20
|
+
init_gost_hash_ctx(&ctx, b);
|
21
|
+
|
22
|
+
if (hash_data(&ctx, data, sum))
|
23
|
+
{
|
24
|
+
return 1;
|
25
|
+
}
|
26
|
+
else
|
27
|
+
return 0;
|
28
|
+
}
|
29
|
+
|
30
|
+
int hash_data(gost_hash_ctx *ctx, const char *data, char *sum)
|
31
|
+
{
|
32
|
+
int i;
|
33
|
+
size_t bytes = strlen(data);
|
34
|
+
|
35
|
+
start_hash(ctx);
|
36
|
+
|
37
|
+
if(bytes > 0)
|
38
|
+
hash_block(ctx, data, bytes);
|
39
|
+
|
40
|
+
finish_hash(ctx, sum);
|
41
|
+
|
42
|
+
return 1;
|
43
|
+
}
|
44
|
+
|
45
|
+
static VALUE rb_gost_digest(VALUE self)
|
46
|
+
{
|
47
|
+
char sum[32];
|
48
|
+
|
49
|
+
VALUE data;
|
50
|
+
|
51
|
+
data = rb_iv_get(self, "@data");
|
52
|
+
|
53
|
+
if( digest(StringValuePtr(data), sum) )
|
54
|
+
return rb_str_new2( substring(sum, 0, 32) );
|
55
|
+
else
|
56
|
+
return Qfalse;
|
57
|
+
}
|
58
|
+
|
59
|
+
/* Ruby Extension initializer */
|
60
|
+
void Init_xmldsign_ext() {
|
61
|
+
mXmldsign = rb_define_module("Xmldsign");
|
62
|
+
mDigests = rb_define_module_under(mXmldsign, "Digests");
|
63
|
+
cGost = rb_define_class_under(mDigests, "Gost", rb_cObject);
|
64
|
+
|
65
|
+
rb_define_method(cGost, "binary", rb_gost_digest, 0);
|
66
|
+
}
|
@@ -0,0 +1,18 @@
|
|
1
|
+
#ifndef XMLDSIGN_EXT_H
|
2
|
+
#define XMLDSIGN_EXT_H
|
3
|
+
|
4
|
+
#include <ruby.h>
|
5
|
+
|
6
|
+
#include <stdio.h>
|
7
|
+
#include <stdlib.h>
|
8
|
+
#include <unistd.h>
|
9
|
+
#include <limits.h>
|
10
|
+
#include <string.h>
|
11
|
+
|
12
|
+
#include "gost89.h"
|
13
|
+
#include "gosthash.h"
|
14
|
+
|
15
|
+
VALUE mXmldsign, mDigests, cGost;
|
16
|
+
|
17
|
+
|
18
|
+
#endif /* ifndef XMLDSIGN_EXT_H */
|
@@ -0,0 +1,84 @@
|
|
1
|
+
module Xmldsign
|
2
|
+
module Algorithms
|
3
|
+
def factory(uri, node)
|
4
|
+
ALGORITHMS[uri].new(node)
|
5
|
+
end
|
6
|
+
|
7
|
+
class Gostr3411
|
8
|
+
def initialize(transform_node)
|
9
|
+
end
|
10
|
+
|
11
|
+
def execute(xml)
|
12
|
+
Digests::Gost.base64(xml)
|
13
|
+
end
|
14
|
+
|
15
|
+
def openssl
|
16
|
+
@engine.digest(KEY)
|
17
|
+
end
|
18
|
+
end
|
19
|
+
|
20
|
+
class Enveloped
|
21
|
+
def initialize(transform_node)
|
22
|
+
end
|
23
|
+
|
24
|
+
def execute(doc)
|
25
|
+
doc.find_first('.//ds:Signature').remove!
|
26
|
+
doc
|
27
|
+
end
|
28
|
+
end
|
29
|
+
|
30
|
+
class XSLT
|
31
|
+
attr_reader :transform_node
|
32
|
+
|
33
|
+
def initialize(transform_node)
|
34
|
+
@transform_node = transform_node
|
35
|
+
end
|
36
|
+
|
37
|
+
def stylesheet
|
38
|
+
doc = LibXML::XML::Document.new
|
39
|
+
doc.root = transform_node.find('*[1]').first.copy(true)
|
40
|
+
LibXSLT::XSLT::Stylesheet.new(doc)
|
41
|
+
end
|
42
|
+
|
43
|
+
def execute(doc)
|
44
|
+
stylesheet.apply doc
|
45
|
+
end
|
46
|
+
end
|
47
|
+
|
48
|
+
class Canonicalization
|
49
|
+
XML_C14N_1_0 = 0
|
50
|
+
XML_C14N_EXCLUSIVE_1_0 = 1
|
51
|
+
XML_C14N_1_1 = 2
|
52
|
+
|
53
|
+
attr_reader :transform_node
|
54
|
+
|
55
|
+
def initialize(transform_node)
|
56
|
+
@transform_node = transform_node
|
57
|
+
end
|
58
|
+
|
59
|
+
def execute(doc)
|
60
|
+
raise NotImplementedError
|
61
|
+
end
|
62
|
+
end
|
63
|
+
|
64
|
+
class C14NExc < Canonicalization
|
65
|
+
def execute(doc)
|
66
|
+
doc.canonicalize mode: XML_C14N_EXCLUSIVE_1_0
|
67
|
+
end
|
68
|
+
end
|
69
|
+
|
70
|
+
ALGORITHMS = {
|
71
|
+
# Digests
|
72
|
+
|
73
|
+
"http://www.w3.org/2001/04/xmldsig-more#gostr3411" => Gostr3411,
|
74
|
+
|
75
|
+
# Transforms and Canonicalize
|
76
|
+
|
77
|
+
"http://www.w3.org/2000/09/xmldsig#enveloped-signature" => Enveloped,
|
78
|
+
"http://www.w3.org/TR/1999/REC-xslt-19991116" => XSLT,
|
79
|
+
"http://www.w3.org/2001/10/xml-exc-c14n#" => C14NExc,
|
80
|
+
}
|
81
|
+
|
82
|
+
module_function :factory
|
83
|
+
end
|
84
|
+
end
|
@@ -0,0 +1,30 @@
|
|
1
|
+
require "xmldsign/xmldsign_ext"
|
2
|
+
|
3
|
+
module Xmldsign
|
4
|
+
module Digests
|
5
|
+
class Gost
|
6
|
+
attr_reader :data
|
7
|
+
|
8
|
+
class << self
|
9
|
+
def base64(data)
|
10
|
+
new(data).base64
|
11
|
+
end
|
12
|
+
def hex(data)
|
13
|
+
new(data).hex
|
14
|
+
end
|
15
|
+
end
|
16
|
+
|
17
|
+
def initialize(data)
|
18
|
+
@data = data
|
19
|
+
end
|
20
|
+
|
21
|
+
def base64
|
22
|
+
Base64.encode64(binary).strip
|
23
|
+
end
|
24
|
+
|
25
|
+
def hex
|
26
|
+
binary.bytes.inject("") { |hex, b| hex << b.to_s(16) }
|
27
|
+
end
|
28
|
+
end
|
29
|
+
end
|
30
|
+
end
|
@@ -0,0 +1,19 @@
|
|
1
|
+
module Xmldsign
|
2
|
+
class Document < DelegateClass(XML::Document)
|
3
|
+
def self.string(xml)
|
4
|
+
new LibXML::XML::Document.string(xml)
|
5
|
+
end
|
6
|
+
|
7
|
+
def signature
|
8
|
+
if (node = find_first('.//ds:Signature'))
|
9
|
+
Signature.new node
|
10
|
+
else
|
11
|
+
raise Xmldsign::NodeError, 'node ds:Signature is not found in document'
|
12
|
+
end
|
13
|
+
end
|
14
|
+
|
15
|
+
def signed
|
16
|
+
signature.sign
|
17
|
+
end
|
18
|
+
end
|
19
|
+
end
|
@@ -0,0 +1,64 @@
|
|
1
|
+
module Xmldsign
|
2
|
+
class Signature < DelegateClass(XML::Node)
|
3
|
+
XML_C14N_1_0 = 0
|
4
|
+
XML_C14N_EXCLUSIVE_1_0 = 1
|
5
|
+
XML_C14N_1_1 = 2
|
6
|
+
|
7
|
+
def signed_info
|
8
|
+
SignedInfo.new find_first('.//ds:SignedInfo')
|
9
|
+
end
|
10
|
+
|
11
|
+
def c14n_signed_info
|
12
|
+
sign
|
13
|
+
doc = LibXML::XML::Document.new
|
14
|
+
doc.root = signed_info.copy(true)
|
15
|
+
doc.canonicalize mode: XML_C14N_EXCLUSIVE_1_0
|
16
|
+
end
|
17
|
+
|
18
|
+
def canonicalization_method
|
19
|
+
node = find_first('.//ds:CanonicalizationMethod')
|
20
|
+
Algorithms.factory node['Algorithm'], node
|
21
|
+
end
|
22
|
+
|
23
|
+
def digest_method
|
24
|
+
node = find_first('.//ds:DigestMethod')
|
25
|
+
Algorithms.factory node['Algorithm'], node
|
26
|
+
end
|
27
|
+
|
28
|
+
def transforms
|
29
|
+
signed_info.transforms
|
30
|
+
end
|
31
|
+
|
32
|
+
def sign
|
33
|
+
fill_digest!
|
34
|
+
clear_signature_value!
|
35
|
+
clear_certificate!
|
36
|
+
doc
|
37
|
+
end
|
38
|
+
|
39
|
+
def clear_signature_value!
|
40
|
+
if (node = find_first('.//ds:SignatureValue'))
|
41
|
+
node.content = ''
|
42
|
+
end
|
43
|
+
end
|
44
|
+
|
45
|
+
def clear_certificate!
|
46
|
+
if (node = find_first('.//ds:X509Certificate'))
|
47
|
+
node.content = ''
|
48
|
+
end
|
49
|
+
end
|
50
|
+
|
51
|
+
def fill_digest!
|
52
|
+
if (node = find_first('.//ds:DigestValue'))
|
53
|
+
node.content = calculate_digest
|
54
|
+
else
|
55
|
+
raise Xmldsign::NodeError, 'node ds:DigestValue is not found in document'
|
56
|
+
end
|
57
|
+
end
|
58
|
+
|
59
|
+
def calculate_digest
|
60
|
+
digest_method.execute transforms.execute
|
61
|
+
end
|
62
|
+
end
|
63
|
+
end
|
64
|
+
|
@@ -0,0 +1,17 @@
|
|
1
|
+
module Xmldsign
|
2
|
+
class Transforms < DelegateClass(XML::Node)
|
3
|
+
def execute(document=self.doc)
|
4
|
+
doc = LibXML::XML::Document.new
|
5
|
+
doc.root = document.root.copy(true)
|
6
|
+
algorithms.inject(doc) { |d, algorithm| algorithm.execute d }
|
7
|
+
end
|
8
|
+
|
9
|
+
def algorithms
|
10
|
+
find('.//ds:Transform').map { |t| factory(t['Algorithm'], t) }
|
11
|
+
end
|
12
|
+
|
13
|
+
def factory(algorithm, node)
|
14
|
+
Algorithms.factory(algorithm, node)
|
15
|
+
end
|
16
|
+
end
|
17
|
+
end
|
data/lib/xmldsign.rb
ADDED
@@ -0,0 +1,21 @@
|
|
1
|
+
require "xmldsign/version"
|
2
|
+
require "xmldsign/error"
|
3
|
+
require "xmldsign/digests/gost"
|
4
|
+
require "libxml"
|
5
|
+
require "libxslt"
|
6
|
+
require "delegate"
|
7
|
+
require "base64"
|
8
|
+
|
9
|
+
module Xmldsign
|
10
|
+
include LibXML
|
11
|
+
|
12
|
+
class NodeError < Error
|
13
|
+
end
|
14
|
+
|
15
|
+
autoload :Algorithms, 'xmldsign/algorithms'
|
16
|
+
autoload :Document, 'xmldsign/document'
|
17
|
+
autoload :Signature, 'xmldsign/signature'
|
18
|
+
autoload :SignedInfo, 'xmldsign/signed_info'
|
19
|
+
autoload :Transforms, 'xmldsign/transforms'
|
20
|
+
end
|
21
|
+
|