strongswan-5.0.0-5.5.2_asn1_choice.patch
src/libstrongswan/asn1/asn1_parser.c | ||
---|---|---|
1 | 1 |
/* |
2 | 2 |
* Copyright (C) 2006 Martin Will |
3 |
* Copyright (C) 2000-2008 Andreas Steffen |
|
4 |
* |
|
5 |
* Hochschule fuer Technik Rapperswil |
|
3 |
* Copyright (C) 2000-2017 Andreas Steffen |
|
4 |
* HSR Hochschule fuer Technik Rapperswil |
|
6 | 5 |
* |
7 | 6 |
* This program is free software; you can redistribute it and/or modify it |
8 | 7 |
* under the terms of the GNU General Public License as published by the |
... | ... | |
76 | 75 |
* Current parsing pointer for each level |
77 | 76 |
*/ |
78 | 77 |
chunk_t blobs[ASN1_MAX_LEVEL + 2]; |
78 | ||
79 |
/** |
|
80 |
* Parsing a CHOICE on the current level ? |
|
81 |
*/ |
|
82 |
bool choice[ASN1_MAX_LEVEL + 2]; |
|
83 | ||
79 | 84 |
}; |
80 | 85 | |
81 | 86 |
METHOD(asn1_parser_t, iterate, bool, |
82 | 87 |
private_asn1_parser_t *this, int *objectID, chunk_t *object) |
83 | 88 |
{ |
84 |
chunk_t *blob, *blob1; |
|
89 |
chunk_t *blob, *blob1, blob_ori;
|
|
85 | 90 |
u_char *start_ptr; |
86 | 91 |
u_int level; |
87 | 92 |
asn1Object_t obj; |
... | ... | |
97 | 102 |
return FALSE; |
98 | 103 |
} |
99 | 104 | |
100 |
if (obj.flags & ASN1_END) /* end of loop or option found */ |
|
105 |
if (obj.flags & ASN1_END) /* end of loop or choice or option found */
|
|
101 | 106 |
{ |
102 | 107 |
if (this->loopAddr[obj.level] && this->blobs[obj.level+1].len > 0) |
103 | 108 |
{ |
... | ... | |
106 | 111 |
} |
107 | 112 |
else |
108 | 113 |
{ |
109 |
this->loopAddr[obj.level] = 0; /* exit loop or option*/ |
|
114 |
this->loopAddr[obj.level] = 0; /* exit loop */ |
|
115 | ||
116 |
if (obj.flags & ASN1_CHOICE) /* end of choices */ |
|
117 |
{ |
|
118 |
if (this->choice[obj.level+1]) |
|
119 |
{ |
|
120 |
DBG1(DBG_ASN, "L%d - %s: incorrect choice encoding", |
|
121 |
this->level0 + obj.level, obj.name); |
|
122 |
this->success = FALSE; |
|
123 |
goto end; |
|
124 |
} |
|
125 |
} |
|
126 | ||
127 |
if (obj.flags & ASN1_CH) /* end of choice */ |
|
128 |
{ |
|
129 |
/* parsed a valid choice */ |
|
130 |
this->choice[obj.level] = FALSE; |
|
131 | ||
132 |
/* advance to end of choices */ |
|
133 |
do |
|
134 |
{ |
|
135 |
this->line++; |
|
136 |
} |
|
137 |
while (!((this->objects[this->line].flags & ASN1_END) && |
|
138 |
(this->objects[this->line].flags & ASN1_CHOICE) && |
|
139 |
(this->objects[this->line].level == obj.level-1))); |
|
140 |
this->line--; |
|
141 |
} |
|
142 | ||
110 | 143 |
goto end; |
111 | 144 |
} |
112 | 145 |
} |
113 | 146 | |
114 | 147 |
level = this->level0 + obj.level; |
115 | 148 |
blob = this->blobs + obj.level; |
149 |
blob_ori = *blob; |
|
116 | 150 |
blob1 = blob + 1; |
117 | 151 |
start_ptr = blob->ptr; |
118 | 152 | |
... | ... | |
129 | 163 |
} |
130 | 164 | |
131 | 165 |
/* handle ASN.1 options */ |
132 | ||
133 | 166 |
if ((obj.flags & ASN1_OPT) |
134 | 167 |
&& (blob->len == 0 || *start_ptr != obj.type)) |
135 | 168 |
{ |
... | ... | |
144 | 177 |
} |
145 | 178 | |
146 | 179 |
/* an ASN.1 object must possess at least a tag and length field */ |
147 | ||
148 | 180 |
if (blob->len < 2) |
149 | 181 |
{ |
150 | 182 |
DBG1(DBG_ASN, "L%d - %s: ASN.1 object smaller than 2 octets", |
... | ... | |
167 | 199 |
blob->ptr += blob1->len; |
168 | 200 |
blob->len -= blob1->len; |
169 | 201 | |
170 |
/* return raw ASN.1 object without prior type checking */ |
|
202 |
/* handle ASN.1 choice without explicit context encoding */ |
|
203 |
if ((obj.flags & ASN1_CHOICE) && obj.type == ASN1_EOC) |
|
204 |
{ |
|
205 |
DBG2(DBG_ASN, "L%d - %s:", level, obj.name); |
|
206 |
this->choice[obj.level+1] = TRUE; |
|
207 |
*blob1 = blob_ori; |
|
208 |
goto end; |
|
209 |
} |
|
171 | 210 | |
211 |
/* return raw ASN.1 object without prior type checking */ |
|
172 | 212 |
if (obj.flags & ASN1_RAW) |
173 | 213 |
{ |
174 | 214 |
DBG2(DBG_ASN, "L%d - %s:", level, obj.name); |
... | ... | |
209 | 249 |
} |
210 | 250 |
} |
211 | 251 | |
252 |
/* In case of a "CHOICE" start to scan for exactly one valid choice */ |
|
253 |
if (obj.flags & ASN1_CHOICE) |
|
254 |
{ |
|
255 |
if (blob1->len == 0) |
|
256 |
{ |
|
257 |
DBG1(DBG_ASN, "L%d - %s: contains no choice", level, obj.name); |
|
258 |
this->success = FALSE; |
|
259 |
goto end; |
|
260 |
} |
|
261 |
this->choice[obj.level+1] = TRUE; |
|
262 |
} |
|
263 | ||
212 | 264 |
if (obj.flags & ASN1_OBJ) |
213 | 265 |
{ |
214 | 266 |
object->ptr = start_ptr; |
src/libstrongswan/asn1/asn1_parser.h | ||
---|---|---|
1 | 1 |
/* |
2 | 2 |
* Copyright (C) 2006 Martin Will |
3 |
* Copyright (C) 2000-2008 Andreas Steffen |
|
4 |
* |
|
5 |
* Hochschule fuer Technik Rapperswil |
|
3 |
* Copyright (C) 2000-2017 Andreas Steffen |
|
4 |
* HSR Hochschule fuer Technik Rapperswil |
|
6 | 5 |
* |
7 | 6 |
* This program is free software; you can redistribute it and/or modify it |
8 | 7 |
* under the terms of the GNU General Public License as published by the |
... | ... | |
32 | 31 |
/** |
33 | 32 |
* Definition of ASN.1 flags |
34 | 33 |
*/ |
35 |
#define ASN1_NONE 0x00 |
|
36 |
#define ASN1_DEF 0x01 |
|
37 |
#define ASN1_OPT 0x02 |
|
38 |
#define ASN1_LOOP 0x04 |
|
39 |
#define ASN1_END 0x08 |
|
40 |
#define ASN1_OBJ 0x10 |
|
41 |
#define ASN1_BODY 0x20 |
|
42 |
#define ASN1_RAW 0x40 |
|
43 |
#define ASN1_EXIT 0x80 |
|
34 |
#define ASN1_NONE 0x0000 |
|
35 |
#define ASN1_DEF 0x0001 |
|
36 |
#define ASN1_OPT 0x0002 |
|
37 |
#define ASN1_LOOP 0x0004 |
|
38 |
#define ASN1_CHOICE 0x0008 |
|
39 |
#define ASN1_CH 0x0010 |
|
40 |
#define ASN1_END 0x0020 |
|
41 |
#define ASN1_OBJ 0x0040 |
|
42 |
#define ASN1_BODY 0x0080 |
|
43 |
#define ASN1_RAW 0x0100 |
|
44 |
#define ASN1_EXIT 0x0200 |
|
44 | 45 | |
45 | 46 |
typedef struct asn1Object_t asn1Object_t; |
46 | 47 | |
... | ... | |
51 | 52 |
u_int level; |
52 | 53 |
const u_char *name; |
53 | 54 |
asn1_t type; |
54 |
u_char flags;
|
|
55 |
uint16_t flags;
|
|
55 | 56 |
}; |
56 | 57 | |
57 | 58 |
typedef struct asn1_parser_t asn1_parser_t; |
src/libstrongswan/plugins/x509/x509_cert.c | ||
---|---|---|
2 | 2 |
* Copyright (C) 2000 Andreas Hess, Patric Lichtsteiner, Roger Wegmann |
3 | 3 |
* Copyright (C) 2001 Marco Bertossa, Andreas Schleiss |
4 | 4 |
* Copyright (C) 2002 Mario Strasser |
5 |
* Copyright (C) 2000-2006 Andreas Steffen
|
|
5 |
* Copyright (C) 2000-2017 Andreas Steffen
|
|
6 | 6 |
* Copyright (C) 2006-2009 Martin Willi |
7 | 7 |
* Copyright (C) 2008 Tobias Brunner |
8 |
* Hochschule fuer Technik Rapperswil |
|
8 |
* HSR Hochschule fuer Technik Rapperswil
|
|
9 | 9 |
* |
10 | 10 |
* This program is free software; you can redistribute it and/or modify it |
11 | 11 |
* under the terms of the GNU General Public License as published by the |
... | ... | |
789 | 789 |
* ASN.1 definition of crlDistributionPoints |
790 | 790 |
*/ |
791 | 791 |
static const asn1Object_t crlDistributionPointsObjects[] = { |
792 |
{ 0, "crlDistributionPoints", ASN1_SEQUENCE, ASN1_LOOP }, /* 0 */
|
|
793 |
{ 1, "DistributionPoint", ASN1_SEQUENCE, ASN1_NONE }, /* 1 */
|
|
794 |
{ 2, "distributionPoint", ASN1_CONTEXT_C_0, ASN1_OPT|ASN1_LOOP }, /* 2 */
|
|
795 |
{ 3, "fullName", ASN1_CONTEXT_C_0, ASN1_OPT|ASN1_OBJ }, /* 3 */
|
|
796 |
{ 3, "end choice", ASN1_EOC, ASN1_END }, /* 4 */
|
|
797 |
{ 3, "nameRelToCRLIssuer",ASN1_CONTEXT_C_1, ASN1_OPT|ASN1_BODY }, /* 5 */
|
|
798 |
{ 3, "end choice", ASN1_EOC, ASN1_END }, /* 6 */
|
|
799 |
{ 2, "end opt", ASN1_EOC, ASN1_END }, /* 7 */
|
|
800 |
{ 2, "reasons", ASN1_CONTEXT_C_1, ASN1_OPT|ASN1_BODY }, /* 8 */
|
|
801 |
{ 2, "end opt", ASN1_EOC, ASN1_END }, /* 9 */
|
|
802 |
{ 2, "crlIssuer", ASN1_CONTEXT_C_2, ASN1_OPT|ASN1_OBJ }, /* 10 */
|
|
803 |
{ 2, "end opt", ASN1_EOC, ASN1_END }, /* 11 */
|
|
804 |
{ 0, "end loop", ASN1_EOC, ASN1_END }, /* 12 */
|
|
805 |
{ 0, "exit", ASN1_EOC, ASN1_EXIT }
|
|
792 |
{ 0, "crlDistributionPoints", ASN1_SEQUENCE, ASN1_LOOP }, /* 0 */
|
|
793 |
{ 1, "DistributionPoint", ASN1_SEQUENCE, ASN1_NONE }, /* 1 */
|
|
794 |
{ 2, "distributionPoint", ASN1_CONTEXT_C_0, ASN1_OPT|ASN1_CHOICE }, /* 2 */
|
|
795 |
{ 3, "fullName", ASN1_CONTEXT_C_0, ASN1_OPT|ASN1_OBJ }, /* 3 */
|
|
796 |
{ 3, "end choice", ASN1_EOC, ASN1_END|ASN1_CH }, /* 4 */
|
|
797 |
{ 3, "nameRelToCRLIssuer",ASN1_CONTEXT_C_1, ASN1_OPT|ASN1_BODY }, /* 5 */
|
|
798 |
{ 3, "end choice", ASN1_EOC, ASN1_END|ASN1_CH }, /* 6 */
|
|
799 |
{ 2, "end opt/choices", ASN1_EOC, ASN1_END|ASN1_CHOICE }, /* 7 */
|
|
800 |
{ 2, "reasons", ASN1_CONTEXT_C_1, ASN1_OPT|ASN1_BODY }, /* 8 */
|
|
801 |
{ 2, "end opt", ASN1_EOC, ASN1_END }, /* 9 */
|
|
802 |
{ 2, "crlIssuer", ASN1_CONTEXT_C_2, ASN1_OPT|ASN1_OBJ }, /* 10 */
|
|
803 |
{ 2, "end opt", ASN1_EOC, ASN1_END }, /* 11 */
|
|
804 |
{ 0, "end loop", ASN1_EOC, ASN1_END }, /* 12 */
|
|
805 |
{ 0, "exit", ASN1_EOC, ASN1_EXIT }
|
|
806 | 806 |
}; |
807 | 807 |
#define CRL_DIST_POINTS 1 |
808 | 808 |
#define CRL_DIST_POINTS_FULLNAME 3 |
... | ... | |
910 | 910 |
* ASN.1 definition of nameConstraints |
911 | 911 |
*/ |
912 | 912 |
static const asn1Object_t nameConstraintsObjects[] = { |
913 |
{ 0, "nameConstraints", ASN1_SEQUENCE, ASN1_LOOP }, /* 0 */
|
|
913 |
{ 0, "nameConstraints", ASN1_SEQUENCE, ASN1_NONE }, /* 0 */
|
|
914 | 914 |
{ 1, "permittedSubtrees", ASN1_CONTEXT_C_0, ASN1_OPT|ASN1_LOOP }, /* 1 */ |
915 | 915 |
{ 2, "generalSubtree", ASN1_SEQUENCE, ASN1_BODY }, /* 2 */ |
916 | 916 |
{ 1, "end loop", ASN1_EOC, ASN1_END }, /* 3 */ |
917 | 917 |
{ 1, "excludedSubtrees", ASN1_CONTEXT_C_1, ASN1_OPT|ASN1_LOOP }, /* 4 */ |
918 | 918 |
{ 2, "generalSubtree", ASN1_SEQUENCE, ASN1_BODY }, /* 5 */ |
919 | 919 |
{ 1, "end loop", ASN1_EOC, ASN1_END }, /* 6 */ |
920 |
{ 0, "end loop", ASN1_EOC, ASN1_END }, /* 7 */ |
|
921 | 920 |
{ 0, "exit", ASN1_EOC, ASN1_EXIT } |
922 | 921 |
}; |
923 | 922 |
#define NAME_CONSTRAINT_PERMITTED 2 |
... | ... | |
974 | 973 |
* ASN.1 definition of a certificatePolicies extension |
975 | 974 |
*/ |
976 | 975 |
static const asn1Object_t certificatePoliciesObject[] = { |
977 |
{ 0, "certificatePolicies", ASN1_SEQUENCE, ASN1_LOOP }, /* 0 */ |
|
978 |
{ 1, "policyInformation", ASN1_SEQUENCE, ASN1_NONE }, /* 1 */ |
|
979 |
{ 2, "policyId", ASN1_OID, ASN1_BODY }, /* 2 */ |
|
980 |
{ 2, "qualifiers", ASN1_SEQUENCE, ASN1_OPT|ASN1_LOOP }, /* 3 */ |
|
981 |
{ 3, "qualifierInfo", ASN1_SEQUENCE, ASN1_NONE }, /* 4 */ |
|
982 |
{ 4, "qualifierId", ASN1_OID, ASN1_BODY }, /* 5 */ |
|
983 |
{ 4, "cPSuri", ASN1_IA5STRING, ASN1_OPT|ASN1_BODY }, /* 6 */ |
|
984 |
{ 4, "end choice", ASN1_EOC, ASN1_END }, /* 7 */ |
|
985 |
{ 4, "userNotice", ASN1_SEQUENCE, ASN1_OPT|ASN1_BODY }, /* 8 */ |
|
986 |
{ 5, "explicitText", ASN1_EOC, ASN1_RAW }, /* 9 */ |
|
987 |
{ 4, "end choice", ASN1_EOC, ASN1_END }, /* 10 */ |
|
988 |
{ 2, "end opt/loop", ASN1_EOC, ASN1_END }, /* 12 */ |
|
989 |
{ 0, "end loop", ASN1_EOC, ASN1_END }, /* 13 */ |
|
990 |
{ 0, "exit", ASN1_EOC, ASN1_EXIT } |
|
976 |
{ 0, "certificatePolicies", ASN1_SEQUENCE, ASN1_LOOP }, /* 0 */ |
|
977 |
{ 1, "policyInformation", ASN1_SEQUENCE, ASN1_NONE }, /* 1 */ |
|
978 |
{ 2, "policyId", ASN1_OID, ASN1_BODY }, /* 2 */ |
|
979 |
{ 2, "qualifiers", ASN1_SEQUENCE, ASN1_OPT|ASN1_LOOP }, /* 3 */ |
|
980 |
{ 3, "qualifierInfo", ASN1_SEQUENCE, ASN1_NONE }, /* 4 */ |
|
981 |
{ 4, "qualifierId", ASN1_OID, ASN1_BODY }, /* 5 */ |
|
982 |
{ 4, "qualifier", ASN1_EOC, ASN1_CHOICE }, /* 6 */ |
|
983 |
{ 5, "cPSuri", ASN1_IA5STRING, ASN1_OPT|ASN1_BODY }, /* 7 */ |
|
984 |
{ 5, "end choice", ASN1_EOC, ASN1_END|ASN1_CH }, /* 8 */ |
|
985 |
{ 5, "userNotice", ASN1_SEQUENCE, ASN1_OPT|ASN1_BODY }, /* 9 */ |
|
986 |
{ 6, "explicitText", ASN1_EOC, ASN1_RAW }, /* 10 */ |
|
987 |
{ 5, "end choice", ASN1_EOC, ASN1_END|ASN1_CH }, /* 11 */ |
|
988 |
{ 4, "end choices", ASN1_EOC, ASN1_END|ASN1_CHOICE }, /* 12 */ |
|
989 |
{ 2, "end opt/loop", ASN1_EOC, ASN1_END }, /* 13 */ |
|
990 |
{ 0, "end loop", ASN1_EOC, ASN1_END }, /* 14 */ |
|
991 |
{ 0, "exit", ASN1_EOC, ASN1_EXIT } |
|
991 | 992 |
}; |
992 |
#define CERT_POLICY_ID 2
|
|
993 |
#define CERT_POLICY_QUALIFIER_ID 5
|
|
994 |
#define CERT_POLICY_CPS_URI 6
|
|
995 |
#define CERT_POLICY_EXPLICIT_TEXT 9
|
|
993 |
#define CERT_POLICY_ID 2
|
|
994 |
#define CERT_POLICY_QUALIFIER_ID 5
|
|
995 |
#define CERT_POLICY_CPS_URI 7
|
|
996 |
#define CERT_POLICY_EXPLICIT_TEXT 10
|
|
996 | 997 | |
997 | 998 |
/** |
998 | 999 |
* Parse certificatePolicies |
... | ... | |
1157 | 1158 |
* ASN.1 definition of ipAddrBlocks according to RFC 3779 |
1158 | 1159 |
*/ |
1159 | 1160 |
static const asn1Object_t ipAddrBlocksObjects[] = { |
1160 |
{ 0, "ipAddrBlocks", ASN1_SEQUENCE, ASN1_LOOP }, /* 0 */ |
|
1161 |
{ 1, "ipAddressFamily", ASN1_SEQUENCE, ASN1_NONE }, /* 1 */ |
|
1162 |
{ 2, "addressFamily", ASN1_OCTET_STRING, ASN1_BODY }, /* 2 */ |
|
1163 |
{ 2, "inherit", ASN1_NULL, ASN1_OPT|ASN1_NONE }, /* 3 */ |
|
1164 |
{ 2, "end choice", ASN1_EOC, ASN1_END }, /* 4 */ |
|
1165 |
{ 2, "addressesOrRanges", ASN1_SEQUENCE, ASN1_OPT|ASN1_LOOP }, /* 5 */ |
|
1166 |
{ 3, "addressPrefix", ASN1_BIT_STRING, ASN1_OPT|ASN1_BODY }, /* 6 */ |
|
1167 |
{ 3, "end choice", ASN1_EOC, ASN1_END }, /* 7 */ |
|
1168 |
{ 3, "addressRange", ASN1_SEQUENCE, ASN1_OPT|ASN1_NONE }, /* 8 */ |
|
1169 |
{ 4, "min", ASN1_BIT_STRING, ASN1_BODY }, /* 9 */ |
|
1170 |
{ 4, "max", ASN1_BIT_STRING, ASN1_BODY }, /* 10 */ |
|
1171 |
{ 3, "end choice", ASN1_EOC, ASN1_END }, /* 11 */ |
|
1172 |
{ 2, "end opt/loop", ASN1_EOC, ASN1_END }, /* 12 */ |
|
1173 |
{ 0, "end loop", ASN1_EOC, ASN1_END }, /* 13 */ |
|
1174 |
{ 0, "exit", ASN1_EOC, ASN1_EXIT } |
|
1161 |
{ 0, "ipAddrBlocks", ASN1_SEQUENCE, ASN1_LOOP }, /* 0 */ |
|
1162 |
{ 1, "ipAddressFamily", ASN1_SEQUENCE, ASN1_NONE }, /* 1 */ |
|
1163 |
{ 2, "addressFamily", ASN1_OCTET_STRING, ASN1_BODY }, /* 2 */ |
|
1164 |
{ 2, "ipAddressChoice", ASN1_EOC, ASN1_CHOICE }, /* 3 */ |
|
1165 |
{ 3, "inherit", ASN1_NULL, ASN1_OPT }, /* 4 */ |
|
1166 |
{ 3, "end choice", ASN1_EOC, ASN1_END|ASN1_CH }, /* 5 */ |
|
1167 |
{ 3, "addressesOrRanges", ASN1_SEQUENCE, ASN1_OPT|ASN1_LOOP }, /* 6 */ |
|
1168 |
{ 4, "addressOrRange", ASN1_EOC, ASN1_CHOICE }, /* 7 */ |
|
1169 |
{ 5, "addressPrefix", ASN1_BIT_STRING, ASN1_OPT|ASN1_BODY }, /* 8 */ |
|
1170 |
{ 5, "end choice", ASN1_EOC, ASN1_END|ASN1_CH }, /* 9 */ |
|
1171 |
{ 5, "addressRange", ASN1_SEQUENCE, ASN1_OPT }, /* 10 */ |
|
1172 |
{ 6, "min", ASN1_BIT_STRING, ASN1_BODY }, /* 11 */ |
|
1173 |
{ 6, "max", ASN1_BIT_STRING, ASN1_BODY }, /* 12 */ |
|
1174 |
{ 5, "end choice", ASN1_EOC, ASN1_END|ASN1_CH }, /* 13 */ |
|
1175 |
{ 4, "end choices", ASN1_EOC, ASN1_END|ASN1_CHOICE }, /* 14 */ |
|
1176 |
{ 3, "end loop/choice", ASN1_EOC, ASN1_END|ASN1_CH }, /* 15 */ |
|
1177 |
{ 2, "end choices", ASN1_EOC, ASN1_END|ASN1_CHOICE }, /* 16 */ |
|
1178 |
{ 0, "end loop", ASN1_EOC, ASN1_END }, /* 17 */ |
|
1179 |
{ 0, "exit", ASN1_EOC, ASN1_EXIT } |
|
1175 | 1180 |
}; |
1176 | 1181 |
#define IP_ADDR_BLOCKS_FAMILY 2 |
1177 |
#define IP_ADDR_BLOCKS_INHERIT 3
|
|
1178 |
#define IP_ADDR_BLOCKS_PREFIX 6
|
|
1179 |
#define IP_ADDR_BLOCKS_MIN 9
|
|
1180 |
#define IP_ADDR_BLOCKS_MAX 10
|
|
1182 |
#define IP_ADDR_BLOCKS_INHERIT 4
|
|
1183 |
#define IP_ADDR_BLOCKS_PREFIX 8
|
|
1184 |
#define IP_ADDR_BLOCKS_MIN 11
|
|
1185 |
#define IP_ADDR_BLOCKS_MAX 12
|
|
1181 | 1186 | |
1182 | 1187 |
static bool check_address_object(ts_type_t ts_type, chunk_t object) |
1183 | 1188 |
{ |
1184 |
- |