1 2 #include <petscwebclient.h> 3 4 static BIO *bio_err = NULL; 5 6 #define PASSWORD "password" 7 8 #if defined(PETSC_USE_SSL_CERTIFICATE) 9 static int password_cb(char *buf,int num, int rwflag,void *userdata) 10 { 11 if (num < strlen(PASSWORD)+1) return(0); 12 strcpy(buf,PASSWORD); 13 return(strlen(PASSWORD)); 14 } 15 #endif 16 17 static void sigpipe_handle(int x) 18 { 19 } 20 21 #undef __FUNCT__ 22 #define __FUNCT__ "PetscSSLInitializeContext" 23 /* 24 PetscSSLInitializeContext - Set up an SSL context suitable for initiating HTTPS requests. 25 26 If built with PETSC_USE_SSL_CERTIFICATE requires the user have created a self-signed certificate with 27 28 $ ./CA.pl -newcert (using the passphrase of password) 29 $ cat newkey.pem newcert.pem > sslclient.pem 30 31 and put the resulting file in either the current directory (with the application) or in the home directory. This seems kind of 32 silly but it was all I could figure out. 33 34 */ 35 PetscErrorCode PetscSSLInitializeContext(SSL_CTX **octx) 36 { 37 SSL_CTX *ctx; 38 #if defined(PETSC_USE_SSL_CERTIFICATE) 39 char keyfile[PETSC_MAX_PATH_LEN]; 40 PetscBool exists; 41 PetscErrorCode ierr; 42 #endif 43 44 PetscFunctionBegin; 45 if (!bio_err){ 46 SSL_library_init(); 47 SSL_load_error_strings(); 48 bio_err = BIO_new_fp(stderr,BIO_NOCLOSE); 49 } 50 51 /* Set up a SIGPIPE handler */ 52 signal(SIGPIPE,sigpipe_handle); 53 54 ctx = SSL_CTX_new(SSLv23_method()); 55 56 #if defined(PETSC_USE_SSL_CERTIFICATE) 57 /* Locate keyfile */ 58 ierr = PetscStrcpy(keyfile,"sslclient.pem");CHKERRQ(ierr); 59 ierr = PetscTestFile(keyfile,'r',&exists);CHKERRQ(ierr); 60 if (!exists) { 61 ierr = PetscGetHomeDirectory(keyfile,PETSC_MAX_PATH_LEN);CHKERRQ(ierr); 62 ierr = PetscStrcat(keyfile,"/");CHKERRQ(ierr); 63 ierr = PetscStrcat(keyfile,"sslclient.pem");CHKERRQ(ierr); 64 ierr = PetscTestFile(keyfile,'r',&exists);CHKERRQ(ierr); 65 if (!exists) SETERRQ(PETSC_COMM_SELF,PETSC_ERR_FILE_OPEN,"Unable to locate sslclient.pem file in current directory or home directory"); 66 } 67 68 /* Load our keys and certificates*/ 69 if (!(SSL_CTX_use_certificate_chain_file(ctx,keyfile))) SETERRQ(PETSC_COMM_SELF,PETSC_ERR_FILE_OPEN,"Cannot read certificate file"); 70 71 SSL_CTX_set_default_passwd_cb(ctx,password_cb); 72 if (!(SSL_CTX_use_PrivateKey_file(ctx,keyfile,SSL_FILETYPE_PEM))) SETERRQ(PETSC_COMM_SELF,PETSC_ERR_FILE_OPEN,"Cannot read key file"); 73 #endif 74 75 *octx = ctx; 76 PetscFunctionReturn(0); 77 } 78 79 #undef __FUNCT__ 80 #define __FUNCT__ "PetscSSLDestroyContext" 81 PetscErrorCode PetscSSLDestroyContext(SSL_CTX *ctx) 82 { 83 PetscFunctionBegin; 84 SSL_CTX_free(ctx); 85 PetscFunctionReturn(0); 86 } 87 88 #undef __FUNCT__ 89 #define __FUNCT__ "PetscHTTPBuildRequest" 90 PetscErrorCode PetscHTTPBuildRequest(const char type[],const char url[],const char header[],const char ctype[],const char body[],char **outrequest) 91 { 92 char *request=0; 93 char contentlength[40],contenttype[80],*path,*host; 94 size_t request_len,headlen,bodylen,contentlen,pathlen,hostlen,typelen,contenttypelen = 0; 95 PetscErrorCode ierr; 96 PetscBool flg; 97 98 PetscFunctionBegin; 99 ierr = PetscStrallocpy(url,&host);CHKERRQ(ierr); 100 ierr = PetscStrchr(host,'/',&path);CHKERRQ(ierr); 101 if (!path) SETERRQ1(PETSC_COMM_SELF,PETSC_ERR_ARG_WRONGSTATE,"url must contain / it is %s",url); 102 ierr = PetscStrlen(host,&hostlen);CHKERRQ(ierr); 103 104 ierr = PetscStrchr(url,'/',&path);CHKERRQ(ierr); 105 ierr = PetscStrlen(path,&pathlen);CHKERRQ(ierr); 106 107 if (header) { 108 ierr = PetscStrendswith(header,"\r\n",&flg);CHKERRQ(ierr); 109 if (!flg) SETERRQ(PETSC_COMM_SELF,PETSC_ERR_ARG_WRONG,"header must end with \\r\\n"); 110 } 111 112 ierr = PetscStrlen(type,&typelen);CHKERRQ(ierr); 113 if (ctype) { 114 ierr = PetscSNPrintf(contenttype,80,"Content-Type: %s\r\n",ctype);CHKERRQ(ierr); 115 ierr = PetscStrlen(contenttype,&contenttypelen);CHKERRQ(ierr); 116 } 117 ierr = PetscStrlen(header,&headlen);CHKERRQ(ierr); 118 ierr = PetscStrlen(body,&bodylen);CHKERRQ(ierr); 119 ierr = PetscSNPrintf(contentlength,40,"Content-Length: %d\r\n\r\n",(int)bodylen);CHKERRQ(ierr); 120 ierr = PetscStrlen(contentlength,&contentlen);CHKERRQ(ierr); 121 122 /* Now construct our HTTP request */ 123 request_len = typelen + 1 + pathlen + hostlen + 100 + headlen + contenttypelen + contentlen + bodylen + 1; 124 ierr = PetscMalloc1(request_len,&request);CHKERRQ(ierr); 125 ierr = PetscStrcpy(request,type);CHKERRQ(ierr); 126 ierr = PetscStrcat(request," ");CHKERRQ(ierr); 127 ierr = PetscStrcat(request,path);CHKERRQ(ierr); 128 ierr = PetscStrcat(request," HTTP/1.1\r\nHost: ");CHKERRQ(ierr); 129 ierr = PetscStrcat(request,host);CHKERRQ(ierr); 130 ierr = PetscFree(host);CHKERRQ(ierr); 131 ierr = PetscStrcat(request,"\r\nUser-Agent:PETScClient\r\n");CHKERRQ(ierr); 132 ierr = PetscStrcat(request,header);CHKERRQ(ierr); 133 if (ctype) { 134 ierr = PetscStrcat(request,contenttype);CHKERRQ(ierr); 135 } 136 ierr = PetscStrcat(request,contentlength);CHKERRQ(ierr); 137 ierr = PetscStrcat(request,body);CHKERRQ(ierr); 138 ierr = PetscStrlen(request,&request_len);CHKERRQ(ierr); 139 ierr = PetscInfo1(NULL,"HTTPS request follows: \n%s\n",request);CHKERRQ(ierr); 140 141 *outrequest = request; 142 PetscFunctionReturn(0); 143 } 144 145 146 #undef __FUNCT__ 147 #define __FUNCT__ "PetscHTTPSRequest" 148 /* 149 PetscHTTPSRequest - Send a request to an HTTPS server 150 151 Input Parameters: 152 + type - either "POST" or "GET" 153 . url - URL of request host/path 154 . header - additional header information, may be NULL 155 . ctype - data type of body, for example application/json 156 . body - data to send to server 157 . ssl - obtained with PetscHTTPSConnect() 158 - buffsize - size of buffer 159 160 Output Parameter: 161 . buff - everything returned from server 162 */ 163 PetscErrorCode PetscHTTPSRequest(const char type[],const char url[],const char header[],const char ctype[],const char body[],SSL *ssl,char buff[],size_t buffsize) 164 { 165 char *request; 166 int r; 167 size_t request_len,len; 168 PetscErrorCode ierr; 169 170 PetscFunctionBegin; 171 ierr = PetscHTTPBuildRequest(type,url,header,ctype,body,&request);CHKERRQ(ierr); 172 ierr = PetscStrlen(request,&request_len);CHKERRQ(ierr); 173 174 r = SSL_write(ssl,request,(int)request_len); 175 switch (SSL_get_error(ssl,r)){ 176 case SSL_ERROR_NONE: 177 if (request_len != (size_t)r) SETERRQ(PETSC_COMM_SELF,PETSC_ERR_LIB,"Incomplete write to SSL socket"); 178 break; 179 default: 180 SETERRQ(PETSC_COMM_SELF,PETSC_ERR_LIB,"SSL socket write problem"); 181 } 182 183 /* Now read the server's response, assuming that it's terminated by a close */ 184 r = SSL_read(ssl,buff,(int)buffsize); 185 len = r; 186 switch (SSL_get_error(ssl,r)){ 187 case SSL_ERROR_NONE: 188 break; 189 case SSL_ERROR_ZERO_RETURN: 190 SSL_shutdown(ssl); /* ignore shutdown error message */ 191 break; 192 case SSL_ERROR_SYSCALL: 193 break; 194 default: 195 SETERRQ(PETSC_COMM_SELF,PETSC_ERR_LIB,"SSL read problem"); 196 } 197 buff[len] = 0; /* null terminate string */ 198 ierr = PetscInfo1(NULL,"HTTPS result follows: \n%s\n",buff);CHKERRQ(ierr); 199 200 SSL_free(ssl); 201 ierr = PetscFree(request);CHKERRQ(ierr); 202 PetscFunctionReturn(0); 203 } 204 205 #undef __FUNCT__ 206 #define __FUNCT__ "PetscHTTPRequest" 207 /* 208 PetscHTTPRequest - Send a request to an HTTP server 209 210 Input Parameters: 211 + type - either "POST" or "GET" 212 . url - URL of request host/path 213 . header - additional header information, may be NULL 214 . ctype - data type of body, for example application/json 215 . body - data to send to server 216 . sock - obtained with PetscOpenSocket() 217 - buffsize - size of buffer 218 219 Output Parameter: 220 . buff - everything returned from server 221 */ 222 PetscErrorCode PetscHTTPRequest(const char type[],const char url[],const char header[],const char ctype[],const char body[],int sock,char buff[],size_t buffsize) 223 { 224 char *request; 225 size_t request_len; 226 PetscErrorCode ierr; 227 228 PetscFunctionBegin; 229 ierr = PetscHTTPBuildRequest(type,url,header,ctype,body,&request);CHKERRQ(ierr); 230 ierr = PetscStrlen(request,&request_len);CHKERRQ(ierr); 231 232 ierr = PetscBinaryWrite(sock,request,request_len,PETSC_CHAR,PETSC_FALSE);CHKERRQ(ierr); 233 ierr = PetscFree(request);CHKERRQ(ierr); 234 PetscBinaryRead(sock,buff,buffsize,PETSC_CHAR); 235 buff[buffsize-1] = 0; 236 ierr = PetscInfo1(NULL,"HTTP result follows: \n%s\n",buff);CHKERRQ(ierr); 237 PetscFunctionReturn(0); 238 } 239 240 241 #undef __FUNCT__ 242 #define __FUNCT__ "PetscHTTPSConnect" 243 PetscErrorCode PetscHTTPSConnect(const char host[],int port,SSL_CTX *ctx,int *sock,SSL **ssl) 244 { 245 BIO *sbio; 246 PetscErrorCode ierr; 247 248 PetscFunctionBegin; 249 /* Connect the TCP socket*/ 250 ierr = PetscOpenSocket(host,port,sock);CHKERRQ(ierr); 251 252 /* Connect the SSL socket */ 253 *ssl = SSL_new(ctx); 254 sbio = BIO_new_socket(*sock,BIO_NOCLOSE); 255 SSL_set_bio(*ssl,sbio,sbio); 256 if (SSL_connect(*ssl) <= 0) SETERRQ(PETSC_COMM_SELF,PETSC_ERR_LIB,"SSL connect error"); 257 PetscFunctionReturn(0); 258 } 259 260